Add comprehensive documentation and update deployment paths

Documentation:
- Add ShopDB-API.md with full API reference (all GET/POST endpoints)
- Add detailed docs for Update-ShopfloorPCs-Remote, Invoke-RemoteMaintenance, Update-PC-CompleteAsset
- Add DATA_COLLECTION_PARITY.md comparing local vs remote data collection
- Add HTML versions of all documentation with styled code blocks
- Document software deployment mechanism and how to add new apps
- Document deprecated scripts (Invoke-RemoteAssetCollection, Install-KioskApp)

Script Updates:
- Update deployment source paths to network share (tsgwp00525.wjs.geaerospace.net)
  - InstallDashboard: \\...\scripts\Dashboard\GEAerospaceDashboardSetup.exe
  - InstallLobbyDisplay: \\...\scripts\LobbyDisplay\GEAerospaceLobbyDisplaySetup.exe
  - UpdateEMxAuthToken: \\...\scripts\eMx\eMxInfo.txt
  - DeployUDCWebServerConfig: \\...\scripts\UDC\udc_webserver_settings.json
- Update machine network detection to include 100.0.0.* for CMM cases
- Rename PC Type #9 from "Part Marker" to "Inspection"

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
cproudlock
2026-02-06 11:45:00 -05:00
parent f40b79c087
commit 7d3519f613
15 changed files with 8774 additions and 40 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,459 @@
# Data Collection Parity Reference
Comprehensive comparison of data fields collected by the remote and local PowerShell scripts, including collection methods and API mapping.
## Table of Contents
- [Overview](#overview)
- [Scripts Compared](#scripts-compared)
- [Quick Reference Tables](#quick-reference-tables)
- [Detailed Field Reference](#detailed-field-reference)
- [Collection Methods](#collection-methods)
- [API Parameter Mapping](#api-parameter-mapping)
- [Testing Parity](#testing-parity)
- [Known Differences](#known-differences)
---
## Overview
Both the remote and local collection scripts are designed to collect the same data fields for shopfloor PCs. This document provides a comprehensive reference for what data is collected, how it's collected, and any differences between the two approaches.
**Goal:** Any field collected by one script should also be collected by the other (where technically feasible).
---
## Scripts Compared
| Aspect | Remote Script | Local Script |
|--------|---------------|--------------|
| **Name** | Update-ShopfloorPCs-Remote.ps1 | Update-PC-CompleteAsset.ps1 |
| **Location** | `S:\dt\shopfloor\scripts\remote-execution\` | `S:\dt\shopfloor\scripts\complete-asset\` |
| **Execution** | From admin workstation via WinRM | Directly on target PC |
| **Context** | SYSTEM via WinRM | Local user or SYSTEM |
| **Batch Support** | Yes (many PCs) | No (one PC at a time) |
| **WinRM Required** | Yes | No |
---
## Quick Reference Tables
### Complete Field Parity Status
| Category | Field | Remote | Local | Parity |
|----------|-------|:------:|:-----:|:------:|
| **System** | Hostname | ✓ | ✓ | ✓ |
| | Serial Number | ✓ | ✓ | ✓ |
| | Service Tag | ✓ | ✓ | ✓ |
| | Manufacturer | ✓ | ✓ | ✓ |
| | Model | ✓ | ✓ | ✓ |
| | Total Physical Memory | ✓ | ✓ | ✓ |
| | Domain Role | ✓ | ✓ | ✓ |
| | OS Version | ✓ | ✓ | ✓ |
| | Last Boot Time | ✓ | ✓ | ✓ |
| | Current Time Zone | ✓ | ✓ | ✓ |
| | Logged In User | ✓ | ✓ | ✓ |
| | PC Type | ✓ | ✓ | ✓ |
| | Machine No | ✓ | ✓ | ✓ |
| **DNC** | Site | ✓ | ✓ | ✓ |
| | CNC | ✓ | ✓ | ✓ |
| | NcIF | ✓ | ✓ | ✓ |
| | Host Type | ✓ | ✓ | ✓ |
| | FTP Primary | ✓ | ✓ | ✓ |
| | FTP Secondary | ✓ | ✓ | ✓ |
| **GE Registry** | 32-bit Present | ✓ | ✓ | ✓ |
| | 64-bit Present | ✓ | ✓ | ✓ |
| | Dual Path Enabled | ✓ | ✓ | ✓ |
| | Path 1 Name | ✓ | ✓ | ✓ |
| | Path 2 Name | ✓ | ✓ | ✓ |
| **Network** | Interface Name | ✓ | ✓ | ✓ |
| | IP Address | ✓ | ✓ | ✓ |
| | Subnet Mask | ✓ | ✓ | ✓ |
| | Default Gateway | ✓ | ✓ | ✓ |
| | MAC Address | ✓ | ✓ | ✓ |
| | Is DHCP | ✓ | ✓ | ✓ |
| | Is Active | ✓ | ✓ | ✓ |
| | Is Machine Network | ✓ | ✓ | ✓ |
| | Is Primary | ✓ | ✓ | ✓ |
| **Apps** | Serial Ports | ✓ | ✓ | ✓ |
| | Has VNC | ✓ | ✓ | ✓ |
| | All Installed Apps | ✓ | ✓ | ✓ |
| | Tracked Applications | ✓ | ✓ | ✓ |
| | UDC Running | ✓ | ✓ | ✓ |
| | CLM Running | ✓ | ✓ | ✓ |
| **Printer** | Default Printer FQDN | ✓ | ✓ | ✓ |
| **Local Only** | V-Drive Access | ✗ | ✓ | N/A |
| | C:\Apps Folder | ✗ | ✓ | N/A |
**Legend:** ✓ = Collected, ✗ = Not collected, N/A = Not applicable
---
## Detailed Field Reference
### Basic System Information
#### Hostname
- **Description:** Computer name of the target PC
- **Remote:** `$env:COMPUTERNAME` inside Invoke-Command scriptblock
- **Local:** `$env:COMPUTERNAME`
- **API Parameter:** `hostname`
- **Example:** `SHOPFLOOR-PC01`
#### Serial Number
- **Description:** BIOS serial number (Dell service tag)
- **Remote:** `(Get-CimInstance -Class CIM_BIOSElement).SerialNumber`
- **Local:** `(Get-CimInstance -Class CIM_BIOSElement).SerialNumber`
- **API Parameter:** `serialNumber`
- **Example:** `ABC1234567`
#### Service Tag
- **Description:** Dell service tag (same as serial for Dell systems)
- **Remote:** Same as SerialNumber
- **Local:** Same as SerialNumber
- **API Parameter:** `serviceTag`
- **Example:** `ABC1234567`
#### Total Physical Memory
- **Description:** Total RAM in gigabytes
- **Remote:** `[Math]::Round($computerSystem.TotalPhysicalMemory / 1GB, 2)`
- **Local:** `[Math]::Round($computerSystem.TotalPhysicalMemory / 1GB, 2)`
- **API Parameter:** `totalPhysicalMemory`
- **Example:** `16.0`
#### Domain Role
- **Description:** Domain membership type
- **Remote:** `$computerSystem.DomainRole`
- **Local:** `$computerSystem.DomainRole`
- **API Parameter:** `domainRole`
- **Values:**
- 0 = Standalone Workstation
- 1 = Member Workstation
- 2 = Standalone Server
- 3 = Member Server
- 4 = Backup Domain Controller
- 5 = Primary Domain Controller
#### Current Time Zone
- **Description:** System timezone setting
- **Remote:** `(Get-TimeZone).Id`
- **Local:** `(Get-TimeZone).Id`
- **API Parameter:** `currentTimeZone`
- **Example:** `Eastern Standard Time`
#### PC Type
- **Description:** Classification based on installed software
- **Remote:** Detection function in scriptblock
- **Local:** `Get-PCType` function
- **API Parameter:** `pcType`
- **Values:** Dashboard, Lobby Display, CMM, Wax Trace, Keyence, EAS1000, Genspect, Heat Treat, Inspection, Shopfloor, Engineer, Standard
---
### DNC Configuration
#### DNC General Settings
- **Description:** Machine DNC settings from GE Aircraft Engines registry
- **Remote:** Read from `HKLM:\SOFTWARE\[WOW6432Node\]GE Aircraft Engines\DNC\General`
- **Local:** Read from same registry path via `Get-DNCConfig`
- **API Parameter:** `dncConfig` (JSON object)
**DNC Config Fields:**
| Field | Registry Key | API Key |
|-------|-------------|---------|
| Site | Site | dncConfig.Site |
| CNC | Cnc | dncConfig.CNC |
| NcIF | NcIF | dncConfig.NcIF |
| Machine No | MachineNo | dncConfig.MachineNo |
| Host Type | HostType | dncConfig.HostType |
| FTP Primary | FtpHostPrimary | dncConfig.FtpHostPrimary |
| FTP Secondary | FtpHostSecondary | dncConfig.FtpHostSecondary |
---
### GE Registry Information
#### Registry Presence
- **Description:** Whether GE Aircraft Engines registry exists
- **32-bit Path:** `HKLM:\SOFTWARE\GE Aircraft Engines`
- **64-bit Path:** `HKLM:\SOFTWARE\WOW6432Node\GE Aircraft Engines`
- **API Parameters:**
- `dncGeRegistry32Bit` (1 or 0)
- `dncGeRegistry64Bit` (1 or 0)
#### Dual Path Configuration
- **Description:** eFocas dual-path settings for redundant machine connections
- **Registry Path:** `...\DNC\eFocas`
- **API Parameters:**
- `dncDualPathEnabled` (1, 0, or null)
- `dncPath1Name` (string)
- `dncPath2Name` (string)
---
### Network Interfaces
Both scripts collect all active network interfaces with these fields:
| Field | Description | API Key |
|-------|-------------|---------|
| InterfaceName | Adapter name | interfaceName |
| IPAddress | IPv4 address | ipAddress |
| SubnetMask | CIDR prefix length | subnetMask |
| DefaultGateway | Gateway address | defaultGateway |
| MACAddress | Physical address | macAddress |
| IsDHCP | DHCP enabled | isDhcp |
| IsActive | Interface is up | isActive |
| IsMachineNetwork | 192.168.*.* or 100.0.0.* address | isMachineNetwork |
| IsPrimary | 10.134.*.* address | isPrimary |
**Network Classification:**
- **IsPrimary = 1:** IP matches `^10\.134\.` (corporate network)
- **IsMachineNetwork = 1:** IP matches `^192\.168\.` or `^100\.0\.0\.` (machine network, includes CMM cases)
---
### Application Detection
#### Serial Ports
- **Description:** List of COM ports for DNC communication
- **Collection:** `Get-CimInstance -ClassName Win32_SerialPort`
- **API Parameter:** `serialPorts` (JSON array)
- **Example:**
```json
[
{"PortName": "COM1", "Description": "Communications Port"},
{"PortName": "COM3", "Description": "USB Serial Port"}
]
```
#### VNC Detection
- **Description:** Whether VNC Server is installed
- **Collection Methods:**
1. Registry check for VNC Server/Connect/RealVNC in Uninstall keys
2. Service check for `vncserver*` services
- **API Parameter:** `hasVnc` (1 or 0)
#### All Installed Applications
- **Description:** Complete list of installed software
- **Collection Locations:**
- `HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*`
- `HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*`
- `HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*`
- `Registry::HKU\<SID>\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*`
- **API Parameters:**
- `allInstalledApps` (pipe-delimited string)
- `allInstalledAppsCount` (integer)
#### Tracked Applications
- **Description:** Applications matched against `applications.csv`
- **API Parameter:** `installedApplications` (JSON array)
- **Example:**
```json
[
{"appid": 2, "appname": "UDC", "version": "2.1.0", "isactive": 1},
{"appid": 15, "appname": "Tanium", "version": "7.4.2", "isactive": 1}
]
```
---
### Printer Information
#### Default Printer FQDN
- **Description:** Network printer port name (IP or FQDN)
- **Collection:** `Get-WmiObject -Query "SELECT * FROM Win32_Printer WHERE Default=$true"`
- **Filtering:** Excludes local/virtual printers (USB, LPT, XPS, PDF, etc.)
- **Processing:** Strips trailing underscore and port suffix (e.g., `10.80.92.53_2` → `10.80.92.53`)
- **API Parameter:** `defaultPrinterFQDN`
---
## Collection Methods
### Remote Script Data Flow
```
Admin Workstation Target PC
│ │
│ Invoke-Command (WinRM) │
├───────────────────────────────→│
│ │ ┌─────────────────────┐
│ │ │ Collect data: │
│ │ │ - CIM instances │
│ │ │ - Registry │
│ │ │ - Processes │
│ │ │ - Network config │
│ │ └─────────────────────┘
│ │
│ Return $result hashtable │
│←───────────────────────────────┤
│ │
│ ┌──────────────────────────┐ │
│ │ Send-PCDataToApi │ │
│ │ POST to ShopDB API │ │
│ └──────────────────────────┘ │
│ │
│ HTTP POST to API │
├───────────────────────────────→│ ShopDB Server
```
### Local Script Data Flow
```
Target PC
│ ┌────────────────────────────────┐
│ │ Collect-SystemInfo │
│ │ - CIM instances │
│ │ - Registry │
│ │ - Processes │
│ └────────────────────────────────┘
│ ┌────────────────────────────────┐
│ │ Get-ShopfloorConfigurations │
│ │ - Network interfaces │
│ │ - DNC config │
│ │ - GE Registry │
│ └────────────────────────────────┘
│ ┌────────────────────────────────┐
│ │ Send-CompleteDataToDashboard │
│ │ POST to ShopDB API │
│ └────────────────────────────────┘
│ HTTP POST to API
├───────────────────────────────────→ ShopDB Server
```
---
## API Parameter Mapping
### updateCompleteAsset Action
| Category | API Parameter | Remote Source | Local Source |
|----------|---------------|---------------|--------------|
| **Basic** | hostname | $result.Hostname | $systemInfo.Hostname |
| | serialNumber | $result.SerialNumber | $systemInfo.SerialNumber |
| | serviceTag | $result.ServiceTag | $systemInfo.ServiceTag |
| | manufacturer | $result.Manufacturer | $systemInfo.Manufacturer |
| | model | $result.Model | $systemInfo.Model |
| | pcType | $result.PCType | $systemInfo.PCType |
| | loggedInUser | $result.LoggedInUser | $systemInfo.LoggedInUser |
| | machineNo | $result.MachineNo | $systemInfo.MachineNo |
| | osVersion | $result.OSVersion | $systemInfo.OSVersion |
| | lastBootUpTime | $result.LastBootUpTime | $systemInfo.LastBootUpTime |
| | totalPhysicalMemory | $result.TotalPhysicalMemory | $systemInfo.TotalPhysicalMemory |
| | domainRole | $result.DomainRole | $systemInfo.DomainRole |
| | currentTimeZone | $result.CurrentTimeZone | $systemInfo.CurrentTimeZone |
| **VNC** | hasVnc | $result.HasVnc | $systemInfo.HasVnc |
| **Serial** | serialPorts | $result.SerialPorts (JSON) | $systemInfo.SerialPorts (JSON) |
| **Apps** | allInstalledApps | $result.AllInstalledApps | $systemInfo.AllInstalledApps |
| | allInstalledAppsCount | $result.AllInstalledAppsCount | $systemInfo.AllInstalledAppsCount |
| **Printer** | defaultPrinterFQDN | $result.DefaultPrinterFQDN | Get-DefaultPrinterFQDN |
| **Network** | networkInterfaces | $result.NetworkInterfaces (JSON) | $shopfloorInfo.NetworkInterfaces (JSON) |
| **Comm** | commConfigs | $result.CommConfigs (JSON) | $shopfloorInfo.CommConfigs (JSON) |
| **DNC** | dncConfig | $result.DNCConfig (JSON) | $shopfloorInfo.DNCConfig (JSON) |
| | dncGeRegistry32Bit | $result.GERegistryInfo.Registry32Bit | $shopfloorInfo.GERegistryInfo.Registry32Bit |
| | dncGeRegistry64Bit | $result.GERegistryInfo.Registry64Bit | $shopfloorInfo.GERegistryInfo.Registry64Bit |
| | dncDualPathEnabled | $result.GERegistryInfo.DualPathEnabled | $shopfloorInfo.GERegistryInfo.DualPathEnabled |
| | dncPath1Name | $result.GERegistryInfo.Path1Name | $shopfloorInfo.GERegistryInfo.Path1Name |
| | dncPath2Name | $result.GERegistryInfo.Path2Name | $shopfloorInfo.GERegistryInfo.Path2Name |
---
## Testing Parity
### Manual Parity Test
Run both scripts on the same PC and compare results:
**Step 1: Run Local Script**
```powershell
# On target PC
.\Update-PC-CompleteAsset.ps1 -DashboardURL "http://dev-server/api.asp" > local-output.txt
```
**Step 2: Run Remote Script**
```powershell
# From admin workstation
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "TARGET-PC" -ApiUrl "http://dev-server/api.asp" > remote-output.txt
```
**Step 3: Compare Database Records**
```sql
-- Check if both created/updated the same record
SELECT * FROM machines WHERE hostname = 'TARGET-PC' ORDER BY lastupdated DESC LIMIT 2;
-- Compare specific fields
SELECT hostname, serialnumber, pctype, totalphysicalmemory, domainrole
FROM machines WHERE hostname = 'TARGET-PC';
```
### Automated Parity Check Script
```powershell
# parity-test.ps1
param(
[Parameter(Mandatory)]
[string]$ComputerName,
[PSCredential]$Credential
)
# Run remote collection
$remoteData = .\Update-ShopfloorPCs-Remote.ps1 -ComputerName $ComputerName -Credential $Credential -WhatIf
# Fields to compare
$fields = @(
'Hostname', 'SerialNumber', 'ServiceTag', 'Manufacturer', 'Model',
'TotalPhysicalMemory', 'DomainRole', 'CurrentTimeZone', 'PCType',
'HasVnc', 'AllInstalledAppsCount'
)
# Output comparison
foreach ($field in $fields) {
Write-Host "$field : $($remoteData.$field)"
}
```
---
## Known Differences
### Local-Only Fields
These fields can only be collected by the local script:
| Field | Reason |
|-------|--------|
| V-Drive Access | Requires user's mapped network drives |
| C:\Apps Folder Access | Network permissions differ in WinRM context |
### Context Differences
| Aspect | Remote | Local |
|--------|--------|-------|
| User context | SYSTEM (via WinRM) | Logged-in user or SYSTEM |
| Network drives | Not accessible | Accessible |
| User registry (HKCU) | SYSTEM's HKCU | User's HKCU |
| Per-user apps | Via HKU enumeration | Via HKU + HKCU |
### PC Type Detection
Both scripts use the same detection priority:
1. Dashboard (GE Aerospace Dashboard)
2. Lobby Display (GE Aerospace Lobby Display)
3. CMM (PC-DMIS, goCMM, DODA)
4. Wax Trace (FormTracePak, FormStatusMonitor)
5. Keyence (VR-3000/5000/6000)
6. EAS1000 (GageCal, NI Software)
7. Genspect
8. Heat Treat
9. Inspection (machine number based)
10. Shopfloor (default for domain shop PCs)
**Additional local-only types:**
- Engineer (requires V-Drive AND C:\Apps)
- Standard (default)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,866 @@
# Invoke-RemoteMaintenance.ps1
Remote maintenance toolkit for executing maintenance tasks on shopfloor PCs via WinRM.
## Table of Contents
- [Overview](#overview)
- [API Integration](#api-integration)
- [Prerequisites](#prerequisites)
- [Quick Start](#quick-start)
- [Parameters Reference](#parameters-reference)
- [Available Tasks](#available-tasks)
- [Software Deployment Mechanism](#software-deployment-mechanism)
- [How-To Guides](#how-to-guides)
- [System Repair](#how-to-repair-system-files)
- [Disk Optimization](#how-to-optimize-disks)
- [Service Management](#how-to-manage-services)
- [Time Synchronization](#how-to-fix-time-sync-issues)
- [DNC Configuration](#how-to-update-dnc-configurations)
- [Software Deployment](#how-to-deploy-software)
- [Batch Operations](#how-to-run-batch-operations)
- [Targeting Strategies](#targeting-strategies)
- [Troubleshooting](#troubleshooting)
- [Best Practices](#best-practices)
---
## Overview
This script provides a comprehensive remote maintenance toolkit for managing shopfloor PCs. It executes maintenance tasks via WinRM (Windows Remote Management) and can target PCs individually, by type, by business unit, or all at once.
**Location:** `S:\dt\shopfloor\scripts\remote-execution\Invoke-RemoteMaintenance.ps1`
**Key Features:**
- 19 maintenance tasks available
- Multiple targeting options (by name, type, business unit, or all)
- Concurrent execution with configurable throttling
- Integration with ShopDB for PC discovery
---
## API Integration
When using `-All`, `-PcType`, or `-BusinessUnit` targeting, the script retrieves PC lists from the ShopDB API:
```
GET /api.asp?action=getShopfloorPCs
GET /api.asp?action=getShopfloorPCs&pctypeid=2 # CMM PCs only
GET /api.asp?action=getShopfloorPCs&businessunitid=1 # Specific business unit
```
**PC Type IDs:**
| ID | Type | ID | Type |
|----|------|----|------|
| 1 | Shopfloor | 7 | Heat Treat |
| 2 | CMM | 8 | Engineer |
| 3 | Wax Trace | 9 | Standard |
| 4 | Keyence | 10 | Inspection |
| 5 | EAS1000 | 11 | Dashboard |
| 6 | Genspect | 12 | Lobby Display |
**See:** [ShopDB API Reference](ShopDB-API.html) for complete API documentation.
---
## Prerequisites
### On Your Workstation
1. **PowerShell 5.1 or higher**
2. **Network access to target PCs** (TCP port 5985)
3. **Admin credentials** for target PCs
### On Target PCs
1. **WinRM enabled** (`Enable-PSRemoting -Force`)
2. **Firewall rules** allowing WinRM traffic
### Verify Connectivity
```powershell
# Test WinRM connectivity
Test-WSMan -ComputerName "SHOPFLOOR-PC01"
# Test with credentials
$cred = Get-Credential
Test-WSMan -ComputerName "SHOPFLOOR-PC01" -Credential $cred
```
---
## Quick Start
### Step 1: Get Credentials
```powershell
$cred = Get-Credential -Message "Enter domain admin credentials"
```
### Step 2: Run a Simple Task
```powershell
# Flush DNS on a single PC
.\Invoke-RemoteMaintenance.ps1 -ComputerName "SHOPFLOOR-PC01" -Task FlushDNS -Credential $cred
```
### Step 3: Check Results
The script outputs status for each PC:
```
[SHOPFLOOR-PC01] FlushDNS: SUCCESS
DNS Resolver Cache flushed successfully
```
---
## Parameters Reference
### Targeting Parameters (Mutually Exclusive)
| Parameter | Type | Description |
|-----------|------|-------------|
| `-ComputerName` | string[] | One or more computer names or IPs |
| `-ComputerListFile` | string | Path to text file with hostnames |
| `-All` | switch | Target all shopfloor PCs from ShopDB |
| `-PcType` | string | Target by PC type (see PC Types) |
| `-BusinessUnit` | string | Target by business unit (see Business Units) |
### Task Parameter (Required)
| Parameter | Type | Description |
|-----------|------|-------------|
| `-Task` | string | Maintenance task to execute |
### Optional Parameters
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `-Credential` | PSCredential | Prompt | Remote authentication |
| `-ApiUrl` | string | Production | ShopDB API endpoint |
| `-ThrottleLimit` | int | 5 | Max concurrent sessions |
| `-DnsSuffix` | string | logon.ds.ge.com | DNS suffix for resolution |
### PC Types
```
Standard, Engineer, Shopfloor, CMM, Wax / Trace, Keyence,
Genspect, Heat Treat, Inspection, Dashboard, Lobby Display, Uncategorized
```
### Business Units
```
TBD, Blisk, HPT, Spools, Inspection, Venture, Turn/Burn, DT
```
---
## Available Tasks
### Repair Tasks
| Task | Description | Duration | Impact |
|------|-------------|----------|--------|
| `DISM` | Repair Windows component store | 15-60 min | Low |
| `SFC` | System File Checker scan | 10-30 min | Low |
### Optimization Tasks
| Task | Description | Duration | Impact |
|------|-------------|----------|--------|
| `OptimizeDisk` | TRIM (SSD) or Defrag (HDD) | 5-60 min | Medium |
| `DiskCleanup` | Remove temp files, updates | 5-15 min | Low |
| `ClearUpdateCache` | Clear Windows Update cache | 1-2 min | Low |
| `ClearBrowserCache` | Clear Chrome/Edge cache | 1-2 min | Low |
### Service Tasks
| Task | Description | Duration | Impact |
|------|-------------|----------|--------|
| `RestartSpooler` | Restart Print Spooler | <1 min | Low |
| `FlushDNS` | Clear DNS cache | <1 min | None |
| `RestartWinRM` | Restart WinRM service | <1 min | Temp disconnect |
### Time/Date Tasks
| Task | Description | Duration | Impact |
|------|-------------|----------|--------|
| `SetTimezone` | Set to Eastern Time | <1 min | None |
| `SyncTime` | Force time sync with DC | <1 min | None |
### DNC Tasks
| Task | Description | Duration | Impact |
|------|-------------|----------|--------|
| `UpdateEMxAuthToken` | Update eMx auth from share | 1-2 min | None |
| `DeployUDCWebServerConfig` | Deploy UDC config | 1-2 min | None |
### System Tasks
| Task | Description | Duration | Impact |
|------|-------------|----------|--------|
| `Reboot` | Restart PC (30s delay) | 2-5 min | High |
### Software Deployment Tasks
| Task | Description | Duration | Impact |
|------|-------------|----------|--------|
| `InstallDashboard` | Install GE Dashboard app | 2-5 min | Medium |
| `InstallLobbyDisplay` | Install Lobby Display app | 2-5 min | Medium |
| `UninstallDashboard` | Remove GE Dashboard | 1-2 min | Low |
| `UninstallLobbyDisplay` | Remove Lobby Display | 1-2 min | Low |
---
## Software Deployment Mechanism
### Source File Locations
Deployment tasks require source files to be available before execution:
| Task | Source File Path |
|------|------------------|
| `InstallDashboard` | `\\tsgwp00525.wjs.geaerospace.net\dt\shopfloor\scripts\Dashboard\GEAerospaceDashboardSetup.exe` |
| `InstallLobbyDisplay` | `\\tsgwp00525.wjs.geaerospace.net\dt\shopfloor\scripts\LobbyDisplay\GEAerospaceLobbyDisplaySetup.exe` |
| `UpdateEMxAuthToken` | `\\tsgwp00525.wjs.geaerospace.net\dt\shopfloor\scripts\eMx\eMxInfo.txt` |
| `DeployUDCWebServerConfig` | `\\tsgwp00525.wjs.geaerospace.net\dt\shopfloor\scripts\UDC\udc_webserver_settings.json` |
### How Deployment Works
1. **Pre-flight Check:** Script verifies source file exists
2. **WinRM Session:** Opens remote session to target PC
3. **File Push:** Copies source file to `C:\Windows\Temp\` on remote PC
4. **Execution:** Runs install/copy task using pushed file
5. **Cleanup:** Removes temp file from remote PC
```
+---------------------+ WinRM +---------------------+
| Your Workstation | ------------> | Target PC |
| | | |
| Source Files: | Push File | Temp Location: |
| - Setup.exe | ------------> | C:\Windows\Temp |
| - config.json | | |
| - eMxInfo.txt | Execute | Final Location: |
| (network) | ------------> | C:\Program Files |
+---------------------+ +---------------------+
```
### Directory Structure
Ensure your script directory contains the required files:
```
S:\dt\shopfloor\scripts\remote-execution\
├── Invoke-RemoteMaintenance.ps1
├── GEAerospaceDashboardSetup.exe # For InstallDashboard
├── GEAerospaceLobbyDisplaySetup.exe # For InstallLobbyDisplay
└── udc_webserver_settings.json # For DeployUDCWebServerConfig
```
### eMx Auth Token Details
The `UpdateEMxAuthToken` task:
1. **Source:** `\\tsgwp00525.wjs.geaerospace.net\dt\shopfloor\scripts\eMx\eMxInfo.txt`
2. **Destinations:** (both paths if they exist)
- `C:\Program Files\GE Aircraft Engines\DNC\eMxInfo.txt`
- `C:\Program Files (x86)\GE Aircraft Engines\DNC\eMxInfo.txt`
3. **Backup:** Creates `eMxInfo-old-YYYYMMDD-HHMMSS.txt` before overwriting
4. **Post-action:** Restarts DNC service (`LDnc.exe`)
### UDC Web Server Config Details
The `DeployUDCWebServerConfig` task:
1. **Pre-check:** Verifies UDC is installed (`C:\Program Files\UDC` exists)
2. **Skip:** PCs without UDC are skipped (not counted as failures)
3. **Destination:** `C:\ProgramData\UDC\udc_webserver_settings.json`
4. **Backup:** Creates backup before overwriting
### Dashboard/Lobby Display Install Details
Both kiosk app installers:
1. **Installer type:** Inno Setup (supports `/VERYSILENT`)
2. **Execution:** Silent install with no user prompts
3. **Cleanup:** Installer removed from temp after execution
**Uninstall GUIDs:**
- Dashboard: `{9D9EEE25-4D24-422D-98AF-2ADEDA4745ED}`
- Lobby Display: `{42FFB952-0B72-493F-8869-D957344CA305}`
### Adding New Deployable Applications
To add a new application for deployment, edit the script in two places:
**Step 1: Add to `$KioskAppConfig` hashtable (~line 1388)**
```powershell
$KioskAppConfig = @{
# Existing entries...
# Add new application
'InstallNewApp' = @{
Action = 'Install'
InstallerPath = '\\tsgwp00525.wjs.geaerospace.net\dt\shopfloor\scripts\NewApp\NewAppSetup.exe'
InstallerName = 'NewAppSetup.exe'
AppName = 'New Application Name'
UninstallGuid = '{YOUR-GUID-HERE}' # Find in registry after manual install
}
'UninstallNewApp' = @{
Action = 'Uninstall'
InstallerName = 'NewAppSetup.exe'
AppName = 'New Application Name'
UninstallGuid = '{YOUR-GUID-HERE}'
}
}
```
**Step 2: Add task names to ValidateSet (~line 142)**
```powershell
[ValidateSet(
'DISM', 'SFC', 'OptimizeDisk', 'DiskCleanup', 'ClearUpdateCache',
'RestartSpooler', 'FlushDNS', 'RestartWinRM', 'ClearBrowserCache',
'SetTimezone', 'SyncTime', 'UpdateEMxAuthToken', 'DeployUDCWebServerConfig', 'Reboot',
'InstallDashboard', 'InstallLobbyDisplay', 'UninstallDashboard', 'UninstallLobbyDisplay',
'InstallNewApp', 'UninstallNewApp' # Add new tasks here
)]
[string]$Task
```
**Step 3: Place installer on network share**
```
\\tsgwp00525.wjs.geaerospace.net\dt\shopfloor\scripts\NewApp\NewAppSetup.exe
```
**Finding the Uninstall GUID:**
After manually installing the application on a test PC, find the GUID in registry:
```powershell
# Search for app in registry
Get-ChildItem "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" |
Get-ItemProperty | Where-Object { $_.DisplayName -like "*AppName*" } |
Select-Object DisplayName, PSChildName, UninstallString
```
The `PSChildName` is typically the GUID (e.g., `{9D9EEE25-4D24-422D-98AF-2ADEDA4745ED}`).
**Installer Requirements:**
- Must support silent installation flags
- Inno Setup: `/VERYSILENT /SUPPRESSMSGBOXES /NORESTART`
- MSI: `/qn /norestart`
- NSIS: `/S`
If your installer uses different flags, modify the `InstallKioskApp` scriptblock.
---
## How-To Guides
### How to Repair System Files
**Scenario:** A PC has corrupted system files causing crashes or errors.
#### Option 1: DISM (Component Store Repair)
```powershell
# Run DISM repair on a single PC
.\Invoke-RemoteMaintenance.ps1 -ComputerName "PROBLEM-PC" -Task DISM -Credential $cred
```
**What it does:**
- Downloads missing/corrupted files from Windows Update
- Repairs the Windows component store
- Required before SFC if component store is damaged
**Expected output:**
```
[PROBLEM-PC] DISM: SUCCESS
Deployment Image Servicing and Management tool
The restore operation completed successfully.
```
#### Option 2: SFC (System File Checker)
```powershell
# Run SFC after DISM
.\Invoke-RemoteMaintenance.ps1 -ComputerName "PROBLEM-PC" -Task SFC -Credential $cred
```
**What it does:**
- Scans all protected system files
- Replaces corrupted files from component store
- Creates log at `C:\Windows\Logs\CBS\CBS.log`
**Best Practice - Full Repair Sequence:**
```powershell
# Step 1: Run DISM first
.\Invoke-RemoteMaintenance.ps1 -ComputerName "PROBLEM-PC" -Task DISM -Credential $cred
# Step 2: Run SFC after DISM completes
.\Invoke-RemoteMaintenance.ps1 -ComputerName "PROBLEM-PC" -Task SFC -Credential $cred
# Step 3: Reboot to apply changes
.\Invoke-RemoteMaintenance.ps1 -ComputerName "PROBLEM-PC" -Task Reboot -Credential $cred
```
---
### How to Optimize Disks
**Scenario:** PCs are running slow due to disk fragmentation or lack of TRIM.
#### Single PC Optimization
```powershell
.\Invoke-RemoteMaintenance.ps1 -ComputerName "SLOW-PC" -Task OptimizeDisk -Credential $cred
```
**What it does:**
- Detects drive type (SSD vs HDD)
- For SSDs: Runs TRIM to reclaim deleted blocks
- For HDDs: Runs defragmentation
#### Optimize All CMM PCs (After Hours)
```powershell
# CMM PCs often have large files - optimize overnight
.\Invoke-RemoteMaintenance.ps1 -PcType CMM -Task OptimizeDisk -Credential $cred -ThrottleLimit 3
```
#### Full Cleanup Sequence
```powershell
# Step 1: Clear update cache
.\Invoke-RemoteMaintenance.ps1 -ComputerName "PC01" -Task ClearUpdateCache -Credential $cred
# Step 2: Run disk cleanup
.\Invoke-RemoteMaintenance.ps1 -ComputerName "PC01" -Task DiskCleanup -Credential $cred
# Step 3: Optimize disk
.\Invoke-RemoteMaintenance.ps1 -ComputerName "PC01" -Task OptimizeDisk -Credential $cred
```
---
### How to Fix Stuck Windows Updates
**Scenario:** Windows Update is stuck or failing repeatedly.
```powershell
# Clear the Windows Update cache
.\Invoke-RemoteMaintenance.ps1 -ComputerName "UPDATE-STUCK-PC" -Task ClearUpdateCache -Credential $cred
```
**What it does:**
1. Stops Windows Update service
2. Stops BITS service
3. Clears `C:\Windows\SoftwareDistribution\Download`
4. Restarts services
**After clearing, trigger new update check:**
```powershell
# On the target PC (optional follow-up)
wuauclt /detectnow
```
---
### How to Clear Browser Cache
**Scenario:** CMM or inspection PCs have slow browser performance.
```powershell
# Single PC
.\Invoke-RemoteMaintenance.ps1 -ComputerName "CMM-PC01" -Task ClearBrowserCache -Credential $cred
# All CMM PCs
.\Invoke-RemoteMaintenance.ps1 -PcType CMM -Task ClearBrowserCache -Credential $cred
```
**What it does:**
- Clears Chrome cache directories
- Clears Edge cache directories
- Does NOT clear saved passwords or bookmarks
---
### How to Manage Services
#### Fix Printing Issues
```powershell
# Restart print spooler on a PC with stuck print jobs
.\Invoke-RemoteMaintenance.ps1 -ComputerName "PRINT-PROBLEM-PC" -Task RestartSpooler -Credential $cred
```
**What it does:**
1. Stops Print Spooler service
2. Clears print queue
3. Restarts Print Spooler service
#### Fix DNS Resolution Issues
```powershell
# Flush DNS cache when a PC can't resolve hostnames
.\Invoke-RemoteMaintenance.ps1 -ComputerName "DNS-ISSUE-PC" -Task FlushDNS -Credential $cred
# Flush DNS on all PCs in a business unit
.\Invoke-RemoteMaintenance.ps1 -BusinessUnit Blisk -Task FlushDNS -Credential $cred
```
#### Fix Remote Management Issues
```powershell
# Restart WinRM if subsequent remote commands fail
.\Invoke-RemoteMaintenance.ps1 -ComputerName "WINRM-ISSUE-PC" -Task RestartWinRM -Credential $cred
```
**Note:** Connection will briefly drop during restart.
---
### How to Fix Time Sync Issues
**Scenario:** PC clock is wrong, causing certificate errors or login issues.
#### Set Correct Timezone
```powershell
# Single PC
.\Invoke-RemoteMaintenance.ps1 -ComputerName "WRONG-TIME-PC" -Task SetTimezone -Credential $cred
# All shopfloor PCs
.\Invoke-RemoteMaintenance.ps1 -All -Task SetTimezone -Credential $cred
```
**Sets timezone to:** Eastern Standard Time
#### Force Time Synchronization
```powershell
# Sync time with domain controller
.\Invoke-RemoteMaintenance.ps1 -ComputerName "WRONG-TIME-PC" -Task SyncTime -Credential $cred
```
**Full time fix sequence:**
```powershell
# Step 1: Set correct timezone
.\Invoke-RemoteMaintenance.ps1 -ComputerName "PC01" -Task SetTimezone -Credential $cred
# Step 2: Sync time
.\Invoke-RemoteMaintenance.ps1 -ComputerName "PC01" -Task SyncTime -Credential $cred
```
---
### How to Update DNC Configurations
#### Update eMx Authentication Token
**Scenario:** eMx authentication is failing on DNC PCs.
```powershell
# Single PC
.\Invoke-RemoteMaintenance.ps1 -ComputerName "DNC-PC01" -Task UpdateEMxAuthToken -Credential $cred
# All shopfloor PCs
.\Invoke-RemoteMaintenance.ps1 -All -Task UpdateEMxAuthToken -Credential $cred
```
**What it does:**
1. Backs up existing `eMxInfo.txt` with timestamp
2. Copies new token file from network share
3. Verifies file was updated
#### Deploy UDC Web Server Configuration
**Scenario:** UDC web server settings need to be updated.
```powershell
# Deploy to PCs with UDC installed
.\Invoke-RemoteMaintenance.ps1 -ComputerName "UDC-PC01","UDC-PC02" -Task DeployUDCWebServerConfig -Credential $cred
```
**What it does:**
1. Checks if UDC is installed
2. Backs up existing configuration
3. Deploys new web server settings
4. Does NOT restart UDC (requires manual restart)
---
### How to Deploy Software
#### Install GE Aerospace Dashboard
**Scenario:** Convert a PC to a Dashboard kiosk.
```powershell
# Single PC installation
.\Invoke-RemoteMaintenance.ps1 -ComputerName "NEWKIOSK-01" -Task InstallDashboard -Credential $cred
# Multiple PCs from a list
$kiosks = @("KIOSK-01", "KIOSK-02", "KIOSK-03")
.\Invoke-RemoteMaintenance.ps1 -ComputerName $kiosks -Task InstallDashboard -Credential $cred
```
**What it does:**
1. Copies installer from network share
2. Runs silent installation
3. Configures auto-start
4. Cleans up installer
**After installation:**
- Run data collection to update PC type
- Reboot PC to complete setup
```powershell
# Complete Dashboard deployment sequence
.\Invoke-RemoteMaintenance.ps1 -ComputerName "KIOSK-01" -Task InstallDashboard -Credential $cred
.\Invoke-RemoteMaintenance.ps1 -ComputerName "KIOSK-01" -Task Reboot -Credential $cred
# After reboot, update ShopDB
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "KIOSK-01" -Credential $cred
```
#### Install Lobby Display
```powershell
.\Invoke-RemoteMaintenance.ps1 -ComputerName "LOBBY-01" -Task InstallLobbyDisplay -Credential $cred
```
#### Uninstall Dashboard or Lobby Display
```powershell
# Remove Dashboard
.\Invoke-RemoteMaintenance.ps1 -ComputerName "OLD-KIOSK" -Task UninstallDashboard -Credential $cred
# Remove Lobby Display
.\Invoke-RemoteMaintenance.ps1 -ComputerName "OLD-LOBBY" -Task UninstallLobbyDisplay -Credential $cred
```
---
### How to Reboot PCs
#### Single PC Reboot
```powershell
.\Invoke-RemoteMaintenance.ps1 -ComputerName "PC-TO-REBOOT" -Task Reboot -Credential $cred
```
**Note:** Reboot has a 30-second delay to allow graceful shutdown.
#### Reboot All Dashboard PCs
```powershell
# Reboot all Dashboard PCs (e.g., for software update)
.\Invoke-RemoteMaintenance.ps1 -PcType Dashboard -Task Reboot -Credential $cred
```
#### Reboot All Lobby Display PCs
```powershell
.\Invoke-RemoteMaintenance.ps1 -PcType "Lobby Display" -Task Reboot -Credential $cred
```
#### Reboot PCs by Business Unit
```powershell
# Reboot all HPT PCs during maintenance window
.\Invoke-RemoteMaintenance.ps1 -BusinessUnit HPT -Task Reboot -Credential $cred
```
---
### How to Run Batch Operations
#### Using a Computer List File
Create a text file with one hostname per line:
```text
# shopfloor-pcs.txt
PC001
PC002
PC003
PC004
PC005
```
Run tasks against the list:
```powershell
.\Invoke-RemoteMaintenance.ps1 -ComputerListFile ".\shopfloor-pcs.txt" -Task FlushDNS -Credential $cred
```
#### Running Multiple Tasks in Sequence
```powershell
# Maintenance routine for a PC
$pc = "SHOPFLOOR-PC01"
# Step 1: Clear caches
.\Invoke-RemoteMaintenance.ps1 -ComputerName $pc -Task ClearUpdateCache -Credential $cred
.\Invoke-RemoteMaintenance.ps1 -ComputerName $pc -Task ClearBrowserCache -Credential $cred
# Step 2: Disk cleanup
.\Invoke-RemoteMaintenance.ps1 -ComputerName $pc -Task DiskCleanup -Credential $cred
# Step 3: Repair
.\Invoke-RemoteMaintenance.ps1 -ComputerName $pc -Task DISM -Credential $cred
.\Invoke-RemoteMaintenance.ps1 -ComputerName $pc -Task SFC -Credential $cred
# Step 4: Sync time
.\Invoke-RemoteMaintenance.ps1 -ComputerName $pc -Task SetTimezone -Credential $cred
.\Invoke-RemoteMaintenance.ps1 -ComputerName $pc -Task SyncTime -Credential $cred
# Step 5: Reboot
.\Invoke-RemoteMaintenance.ps1 -ComputerName $pc -Task Reboot -Credential $cred
```
---
## Targeting Strategies
### By Individual PCs
**Best for:** Specific troubleshooting, targeted fixes
```powershell
.\Invoke-RemoteMaintenance.ps1 -ComputerName "PROBLEM-PC" -Task DISM -Credential $cred
```
### By PC Type
**Best for:** Type-specific maintenance, software updates
```powershell
# All CMM PCs
.\Invoke-RemoteMaintenance.ps1 -PcType CMM -Task DiskCleanup -Credential $cred
# All Dashboard kiosks
.\Invoke-RemoteMaintenance.ps1 -PcType Dashboard -Task Reboot -Credential $cred
```
### By Business Unit
**Best for:** Department-specific maintenance windows
```powershell
# All Blisk area PCs
.\Invoke-RemoteMaintenance.ps1 -BusinessUnit Blisk -Task SyncTime -Credential $cred
```
### All Shopfloor PCs
**Best for:** Global maintenance, security updates
```powershell
# Flush DNS everywhere
.\Invoke-RemoteMaintenance.ps1 -All -Task FlushDNS -Credential $cred -ThrottleLimit 10
```
### Using a List File
**Best for:** Custom groups, staged rollouts
```powershell
.\Invoke-RemoteMaintenance.ps1 -ComputerListFile ".\phase1-pcs.txt" -Task DISM -Credential $cred
```
---
## Troubleshooting
### Task Times Out
**Cause:** Task takes longer than session timeout.
**Solution:** DISM and SFC can take a long time. Check if task completed on target:
```powershell
# Check DISM log
Invoke-Command -ComputerName "PC01" -Credential $cred -ScriptBlock {
Get-Content "C:\Windows\Logs\DISM\dism.log" -Tail 50
}
```
### "Access Denied" on Some PCs
**Cause:** Credentials don't have admin rights on that PC.
**Solutions:**
1. Use different credentials
2. Add account to local Administrators group on target
3. Check if UAC is blocking remote admin
### Software Installation Fails
**Cause:** Network share not accessible or installer missing.
**Solutions:**
1. Verify network share path is accessible
2. Check installer exists at expected location
3. Verify credentials can access the share
### Reboot Doesn't Happen
**Cause:** User cancelled shutdown or application blocked it.
**Solutions:**
```powershell
# Force immediate reboot (no 30-second delay)
Invoke-Command -ComputerName "PC01" -Credential $cred -ScriptBlock {
Restart-Computer -Force
}
```
---
## Best Practices
### 1. Start Small
Test on one PC before running against groups:
```powershell
# Test on single PC first
.\Invoke-RemoteMaintenance.ps1 -ComputerName "TEST-PC" -Task DISM -Credential $cred
```
### 2. Use Appropriate Throttle Limits
| Scenario | Recommended ThrottleLimit |
|----------|--------------------------|
| Fast network, light tasks | 10-25 |
| Normal operations | 5 (default) |
| Heavy tasks (DISM, Defrag) | 2-3 |
| Slow network | 2-3 |
### 3. Schedule Disruptive Tasks
Run reboots and heavy tasks during maintenance windows:
- DISM/SFC: After hours
- Disk optimization: After hours
- Reboots: During shift changes or maintenance windows
### 4. Verify Before Rebooting
Always confirm which PCs will be affected:
```powershell
# Check PC type before reboot
.\Update-ShopfloorPCs-Remote.ps1 -PcType Dashboard -WhatIf
```
### 5. Keep Logs
Redirect output for audit trail:
```powershell
.\Invoke-RemoteMaintenance.ps1 -All -Task SyncTime -Credential $cred | Tee-Object -FilePath "maintenance-log-$(Get-Date -Format 'yyyyMMdd').txt"
```

876
docs/ShopDB-API.html Normal file
View File

@@ -0,0 +1,876 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ShopDB API Reference</title>
<style>
* {
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
line-height: 1.6;
max-width: 900px;
margin: 0 auto;
padding: 20px 40px;
background-color: #ffffff;
color: #333;
}
h1 {
color: #1a5276;
border-bottom: 3px solid #1a5276;
padding-bottom: 10px;
margin-top: 0;
}
h2 {
color: #2874a6;
border-bottom: 2px solid #d5dbdb;
padding-bottom: 8px;
margin-top: 40px;
}
h3 {
color: #2e86ab;
margin-top: 30px;
}
h4 {
color: #5d6d7e;
margin-top: 25px;
}
a {
color: #2980b9;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
code {
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
background-color: #f4f4f4;
padding: 2px 6px;
border-radius: 3px;
font-size: 0.9em;
border: 1px solid #e1e1e1;
}
pre {
background-color: #2d2d2d;
color: #f8f8f2;
padding: 15px 20px;
border-radius: 6px;
overflow-x: auto;
font-family: 'Cascadia Mono', 'JetBrains Mono', 'Fira Code', 'Source Code Pro', 'DejaVu Sans Mono', 'Consolas', 'Monaco', 'Courier New', monospace;
font-size: 14px;
line-height: 1.4;
border: 1px solid #444;
margin: 15px 0;
-webkit-font-feature-settings: "liga" 0;
font-feature-settings: "liga" 0;
letter-spacing: 0;
}
pre code {
background-color: transparent;
padding: 0;
border: none;
color: inherit;
font-size: inherit;
}
table {
border-collapse: collapse;
width: 100%;
margin: 15px 0;
font-size: 14px;
}
th, td {
border: 1px solid #ddd;
padding: 10px 12px;
text-align: left;
}
th {
background-color: #34495e;
color: white;
font-weight: 600;
}
tr:nth-child(even) {
background-color: #f9f9f9;
}
tr:hover {
background-color: #f1f1f1;
}
ul, ol {
padding-left: 25px;
}
li {
margin-bottom: 5px;
}
blockquote {
border-left: 4px solid #3498db;
margin: 15px 0;
padding: 10px 20px;
background-color: #f8f9fa;
color: #555;
}
hr {
border: none;
border-top: 2px solid #eee;
margin: 30px 0;
}
.toc {
background-color: #f8f9fa;
border: 1px solid #e9ecef;
border-radius: 6px;
padding: 20px;
margin-bottom: 30px;
}
.toc h2 {
margin-top: 0;
border-bottom: none;
font-size: 1.2em;
}
.toc ul {
list-style-type: none;
padding-left: 0;
}
.toc li {
margin-bottom: 8px;
}
.toc a {
color: #2c3e50;
}
.note {
background-color: #fff3cd;
border-left: 4px solid #ffc107;
padding: 10px 15px;
margin: 15px 0;
}
.warning {
background-color: #f8d7da;
border-left: 4px solid #dc3545;
padding: 10px 15px;
margin: 15px 0;
}
@media print {
body {
max-width: 100%;
padding: 20px;
}
pre {
white-space: pre-wrap;
word-wrap: break-word;
}
h2 {
page-break-before: auto;
}
pre, table {
page-break-inside: avoid;
}
}
</style>
</head>
<body>
<h1 id="shopdb-api-reference">ShopDB API Reference</h1>
<p>REST API for PowerShell data collection scripts and ShopDB integrations.</p>
<h2 id="table-of-contents">Table of Contents</h2>
<ul>
<li><a href="#overview">Overview</a></li>
<li><a href="#base-url">Base URL</a></li>
<li><a href="#authentication">Authentication</a></li>
<li><a href="#endpoints">Endpoints</a></li>
<li><a href="#get-endpoints">GET Endpoints</a></li>
<li><a href="#post-endpoints">POST Endpoints</a></li>
<li><a href="#response-format">Response Format</a></li>
<li><a href="#error-handling">Error Handling</a></li>
<li><a href="#powershell-integration">PowerShell Integration</a></li>
</ul>
<hr>
<h2 id="overview">Overview</h2>
<p>The ShopDB API (<code>api.asp</code>) provides endpoints for:</p>
<ul>
<li><strong>Data Collection</strong>: Receive PC asset data from PowerShell scripts</li>
<li><strong>PC Retrieval</strong>: Query lists of shopfloor PCs for remote management</li>
<li><strong>Maintenance</strong>: Update WinRM status, printer mappings, installed applications</li>
<li><strong>Dashboard</strong>: Health checks and monitoring data</li>
</ul>
<p><strong>Technology</strong>: Classic ASP (VBScript) with MySQL database</p>
<hr>
<h2 id="base-url">Base URL</h2>
<table>
<thead><tr>
<th>Environment</th>
<th>URL</th>
</tr></thead>
<tbody>
<tr>
<td>Production</td>
<td><code>https://tsgwp00525.rd.ds.ge.com/shopdb/api.asp</code></td>
</tr>
<tr>
<td>Development</td>
<td><code>http://192.168.122.151:8080/api.asp</code></td>
</tr>
</tbody></table>
<hr>
<h2 id="authentication">Authentication</h2>
<p>Currently no authentication required. API is accessible from internal network only.</p>
<hr>
<h2 id="endpoints">Endpoints</h2>
<h3 id="get-endpoints">GET Endpoints</h3>
<h4 id="getdashboarddata">getDashboardData</h4>
<p>Health check endpoint to verify API is online.</p>
<p><strong>Request:</strong></p>
<pre><code>GET /api.asp?action=getDashboardData</code></pre>
<p><strong>Response:</strong></p>
<pre><code class="language-json">{
&quot;success&quot;: true,
&quot;message&quot;: &quot;ShopDB API is online - v13 (inlined all queries)&quot;,
&quot;version&quot;: &quot;1.0&quot;,
&quot;schema&quot;: &quot;Phase 2&quot;,
&quot;connStatus&quot;: &quot;objConn is Open&quot;
}</code></pre>
<p><strong>Used By:</strong> Health monitoring, connectivity tests</p>
<hr>
<h4 id="getshopfloorpcs">getShopfloorPCs</h4>
<p>Returns list of all active shopfloor PCs for remote management operations.</p>
<p><strong>Request:</strong></p>
<pre><code>GET /api.asp?action=getShopfloorPCs
GET /api.asp?action=getShopfloorPCs&amp;pctypeid=1
GET /api.asp?action=getShopfloorPCs&amp;businessunitid=2</code></pre>
<p><strong>Query Parameters:</strong></p>
<table>
<thead><tr>
<th>Parameter</th>
<th>Type</th>
<th>Description</th>
</tr></thead>
<tbody>
<tr>
<td><code>pctypeid</code></td>
<td>int</td>
<td>Filter by PC type (optional)</td>
</tr>
<tr>
<td><code>businessunitid</code></td>
<td>int</td>
<td>Filter by business unit (optional)</td>
</tr>
</tbody></table>
<p><strong>PC Type IDs:</strong></p>
<table>
<thead><tr>
<th>ID</th>
<th>Type</th>
</tr></thead>
<tbody>
<tr>
<td>1</td>
<td>Shopfloor</td>
</tr>
<tr>
<td>2</td>
<td>CMM</td>
</tr>
<tr>
<td>3</td>
<td>Wax Trace</td>
</tr>
<tr>
<td>4</td>
<td>Keyence</td>
</tr>
<tr>
<td>5</td>
<td>EAS1000</td>
</tr>
<tr>
<td>6</td>
<td>Genspect</td>
</tr>
<tr>
<td>7</td>
<td>Heat Treat</td>
</tr>
<tr>
<td>8</td>
<td>Engineer</td>
</tr>
<tr>
<td>9</td>
<td>Standard</td>
</tr>
<tr>
<td>10</td>
<td>Inspection</td>
</tr>
<tr>
<td>11</td>
<td>Dashboard</td>
</tr>
<tr>
<td>12</td>
<td>Lobby Display</td>
</tr>
</tbody></table>
<p><strong>Response:</strong></p>
<pre><code class="language-json">{
&quot;success&quot;: true,
&quot;count&quot;: 45,
&quot;data&quot;: [
{
&quot;machineid&quot;: 1234,
&quot;hostname&quot;: &quot;G1ZTNCX3ESF&quot;,
&quot;machinenumber&quot;: &quot;M0612, M0613&quot;,
&quot;serialnumber&quot;: &quot;ABC1234567&quot;,
&quot;ipaddress&quot;: &quot;10.134.50.101&quot;,
&quot;loggedinuser&quot;: &quot;DOMAIN\\jsmith&quot;,
&quot;pctype&quot;: &quot;Shopfloor&quot;,
&quot;pctypeid&quot;: 1,
&quot;businessunit&quot;: &quot;Rotor&quot;,
&quot;businessunitid&quot;: 2,
&quot;lastupdated&quot;: &quot;1/15/2025 8:30 AM&quot;
}
]
}</code></pre>
<p><strong>Notes:</strong></p>
<ul>
<li>Returns only PCs with 10.134.<em>.</em> IP addresses by default</li>
<li>Dashboard (11) and Lobby Display (12) types bypass IP filter</li>
<li>Only includes machinetypeid 33-35 (actual PCs)</li>
</ul>
<p><strong>Used By:</strong> <code>Update-ShopfloorPCs-Remote.ps1 -All</code>, <code>Invoke-RemoteMaintenance.ps1 -All</code></p>
<hr>
<h4 id="gethighuptimepcs">getHighUptimePCs</h4>
<p>Returns PCs that haven't been rebooted in specified number of days.</p>
<p><strong>Request:</strong></p>
<pre><code>GET /api.asp?action=getHighUptimePCs&amp;minUptime=30</code></pre>
<p><strong>Query Parameters:</strong></p>
<table>
<thead><tr>
<th>Parameter</th>
<th>Type</th>
<th>Default</th>
<th>Description</th>
</tr></thead>
<tbody>
<tr>
<td><code>minUptime</code></td>
<td>int</td>
<td>10</td>
<td>Minimum uptime in days</td>
</tr>
</tbody></table>
<p><strong>Response:</strong></p>
<pre><code class="language-json">{
&quot;success&quot;: true,
&quot;count&quot;: 5,
&quot;minUptime&quot;: 30,
&quot;data&quot;: [
{
&quot;machineid&quot;: 1234,
&quot;hostname&quot;: &quot;SHOPFLOOR-01&quot;,
&quot;machinenumber&quot;: &quot;M0612&quot;,
&quot;serialnumber&quot;: &quot;ABC1234567&quot;,
&quot;ipaddress&quot;: &quot;10.134.50.101&quot;,
&quot;loggedinuser&quot;: &quot;DOMAIN\\jsmith&quot;,
&quot;pctype&quot;: &quot;Shopfloor&quot;,
&quot;uptime_days&quot;: 45,
&quot;lastboottime&quot;: &quot;2024-12-01 08:00:00&quot;,
&quot;pctypeid&quot;: 1,
&quot;businessunit&quot;: &quot;Rotor&quot;,
&quot;businessunitid&quot;: 2,
&quot;lastupdated&quot;: &quot;1/15/2025 8:30 AM&quot;
}
]
}</code></pre>
<p><strong>Used By:</strong> <code>Update-ShopfloorPCs-Remote.ps1 -Reboot -MinUptimeDays 30</code></p>
<hr>
<h4 id="getrecordedip">getRecordedIP</h4>
<p>Get the recorded IP address for a specific hostname.</p>
<p><strong>Request:</strong></p>
<pre><code>GET /api.asp?action=getRecordedIP&amp;hostname=G1ZTNCX3ESF</code></pre>
<p><strong>Query Parameters:</strong></p>
<table>
<thead><tr>
<th>Parameter</th>
<th>Type</th>
<th>Description</th>
</tr></thead>
<tbody>
<tr>
<td><code>hostname</code></td>
<td>string</td>
<td>Computer name to look up</td>
</tr>
</tbody></table>
<p><strong>Response:</strong></p>
<pre><code class="language-json">{
&quot;success&quot;: true,
&quot;hostname&quot;: &quot;G1ZTNCX3ESF&quot;,
&quot;ipaddress&quot;: &quot;10.134.50.101&quot;
}</code></pre>
<hr>
<h4 id="getpcmachinerelationships">getPCMachineRelationships</h4>
<p>Returns PCs that have relationships to equipment (machines).</p>
<p><strong>Request:</strong></p>
<pre><code>GET /api.asp?action=getPCMachineRelationships</code></pre>
<p><strong>Response:</strong></p>
<pre><code class="language-json">{
&quot;success&quot;: true,
&quot;count&quot;: 25,
&quot;data&quot;: [
{
&quot;pc_machineid&quot;: 1234,
&quot;pc_hostname&quot;: &quot;G1ZTNCX3ESF&quot;,
&quot;equipment_machineid&quot;: 5678,
&quot;equipment_machinenumber&quot;: &quot;M0612&quot;
}
]
}</code></pre>
<hr>
<h3 id="post-endpoints">POST Endpoints</h3>
<h4 id="updatecompleteasset">updateCompleteAsset</h4>
<p>Main endpoint for PC data collection. Receives comprehensive asset data from PowerShell scripts.</p>
<p><strong>Request:</strong></p>
<pre><code>POST /api.asp
Content-Type: application/x-www-form-urlencoded
action=updateCompleteAsset
&amp;hostname=G1ZTNCX3ESF
&amp;serialNumber=ABC1234567
&amp;manufacturer=Dell Inc.
&amp;model=OptiPlex 7080
&amp;pcType=Shopfloor
&amp;loggedInUser=DOMAIN\jsmith
&amp;machineNo=M0612
&amp;osVersion=Microsoft Windows 10 Enterprise
&amp;lastBootTime=2025-01-15 08:30:00
&amp;hasVnc=1
&amp;hasWinRM=1
&amp;networkInterfaces=[...]
&amp;dncConfig=[...]
&amp;installedApps=[...]</code></pre>
<p><strong>Required Parameters:</strong></p>
<table>
<thead><tr>
<th>Parameter</th>
<th>Type</th>
<th>Description</th>
</tr></thead>
<tbody>
<tr>
<td><code>hostname</code></td>
<td>string</td>
<td>Computer name</td>
</tr>
<tr>
<td><code>serialNumber</code></td>
<td>string</td>
<td>BIOS serial number</td>
</tr>
</tbody></table>
<p><strong>Optional Parameters:</strong></p>
<table>
<thead><tr>
<th>Parameter</th>
<th>Type</th>
<th>Description</th>
</tr></thead>
<tbody>
<tr>
<td><code>manufacturer</code></td>
<td>string</td>
<td>System manufacturer</td>
</tr>
<tr>
<td><code>model</code></td>
<td>string</td>
<td>System model</td>
</tr>
<tr>
<td><code>pcType</code></td>
<td>string</td>
<td>PC classification (Shopfloor, CMM, etc.)</td>
</tr>
<tr>
<td><code>loggedInUser</code></td>
<td>string</td>
<td>Currently logged in user</td>
</tr>
<tr>
<td><code>machineNo</code></td>
<td>string</td>
<td>Associated machine number(s)</td>
</tr>
<tr>
<td><code>osVersion</code></td>
<td>string</td>
<td>Windows version</td>
</tr>
<tr>
<td><code>lastBootTime</code></td>
<td>datetime</td>
<td>Last boot timestamp</td>
</tr>
<tr>
<td><code>hasVnc</code></td>
<td>int</td>
<td>VNC installed (0/1)</td>
</tr>
<tr>
<td><code>hasWinRM</code></td>
<td>int</td>
<td>WinRM enabled (0/1)</td>
</tr>
<tr>
<td><code>networkInterfaces</code></td>
<td>JSON</td>
<td>Network adapter configurations</td>
</tr>
<tr>
<td><code>dncConfig</code></td>
<td>JSON</td>
<td>DNC/FTP settings</td>
</tr>
<tr>
<td><code>installedApps</code></td>
<td>JSON</td>
<td>Tracked applications</td>
</tr>
<tr>
<td><code>warrantyEndDate</code></td>
<td>date</td>
<td>Dell warranty expiration</td>
</tr>
<tr>
<td><code>warrantyStatus</code></td>
<td>string</td>
<td>Warranty status text</td>
</tr>
<tr>
<td><code>dncDualPathEnabled</code></td>
<td>int</td>
<td>Dual path enabled (0/1)</td>
</tr>
<tr>
<td><code>dncPath1Name</code></td>
<td>string</td>
<td>Path 1 name</td>
</tr>
<tr>
<td><code>dncPath2Name</code></td>
<td>string</td>
<td>Path 2 name</td>
</tr>
</tbody></table>
<p><strong>Network Interfaces JSON Format:</strong></p>
<pre><code class="language-json">[
{
&quot;interfaceName&quot;: &quot;Ethernet0&quot;,
&quot;ipAddress&quot;: &quot;10.134.50.101&quot;,
&quot;subnetMask&quot;: &quot;24&quot;,
&quot;defaultGateway&quot;: &quot;10.134.50.1&quot;,
&quot;macAddress&quot;: &quot;00-11-22-33-44-55&quot;,
&quot;isDhcp&quot;: 0,
&quot;isActive&quot;: 1,
&quot;isMachineNetwork&quot;: 0,
&quot;isPrimary&quot;: 1
}
]</code></pre>
<p><strong>DNC Config JSON Format:</strong></p>
<pre><code class="language-json">{
&quot;site&quot;: &quot;WJF&quot;,
&quot;cnc&quot;: &quot;FANUC&quot;,
&quot;ncif&quot;: &quot;FOCAS2&quot;,
&quot;machineNo&quot;: &quot;M0612&quot;,
&quot;ftpPrimary&quot;: &quot;10.134.50.10&quot;,
&quot;ftpSecondary&quot;: &quot;10.134.50.11&quot;
}</code></pre>
<p><strong>Installed Apps JSON Format:</strong></p>
<pre><code class="language-json">[
{
&quot;appid&quot;: 5,
&quot;appname&quot;: &quot;PC-DMIS&quot;,
&quot;version&quot;: &quot;2023.1&quot;,
&quot;isactive&quot;: 1
}
]</code></pre>
<p><strong>Response:</strong></p>
<pre><code class="language-json">{
&quot;success&quot;: true,
&quot;message&quot;: &quot;PC data stored successfully&quot;,
&quot;pcid&quot;: 1234,
&quot;hostname&quot;: &quot;G1ZTNCX3ESF&quot;,
&quot;debugMsg&quot;: &quot;PCType=Shopfloor, DNC=YES, Net=YES&quot;
}</code></pre>
<p><strong>Used By:</strong> <code>Update-ShopfloorPCs-Remote.ps1</code>, <code>Update-PC-CompleteAsset.ps1</code></p>
<hr>
<h4 id="updateprintermapping">updatePrinterMapping</h4>
<p>Links a PC to its default printer.</p>
<p><strong>Request:</strong></p>
<pre><code>POST /api.asp
Content-Type: application/x-www-form-urlencoded
action=updatePrinterMapping
&amp;hostname=G1ZTNCX3ESF
&amp;printerFQDN=printer01.domain.com</code></pre>
<p><strong>Parameters:</strong></p>
<table>
<thead><tr>
<th>Parameter</th>
<th>Type</th>
<th>Description</th>
</tr></thead>
<tbody>
<tr>
<td><code>hostname</code></td>
<td>string</td>
<td>PC hostname</td>
</tr>
<tr>
<td><code>printerFQDN</code></td>
<td>string</td>
<td>Printer FQDN, Windows name, or IP</td>
</tr>
</tbody></table>
<p><strong>Response:</strong></p>
<pre><code class="language-json">{
&quot;success&quot;: true,
&quot;message&quot;: &quot;Printer mapping updated&quot;,
&quot;printerId&quot;: 45,
&quot;machinesUpdated&quot;: 1,
&quot;matchMethod&quot;: &quot;fqdn&quot;
}</code></pre>
<p><strong>Match Methods:</strong> <code>fqdn</code>, <code>windowsname</code>, <code>ip</code></p>
<hr>
<h4 id="updateinstalledapps">updateInstalledApps</h4>
<p>Updates the list of tracked applications installed on a PC.</p>
<p><strong>Request:</strong></p>
<pre><code>POST /api.asp
Content-Type: application/x-www-form-urlencoded
action=updateInstalledApps
&amp;hostname=G1ZTNCX3ESF
&amp;installedApps=[{&quot;appid&quot;:5,&quot;appname&quot;:&quot;PC-DMIS&quot;,&quot;version&quot;:&quot;2023.1&quot;,&quot;isactive&quot;:1}]</code></pre>
<p><strong>Parameters:</strong></p>
<table>
<thead><tr>
<th>Parameter</th>
<th>Type</th>
<th>Description</th>
</tr></thead>
<tbody>
<tr>
<td><code>hostname</code></td>
<td>string</td>
<td>PC hostname</td>
</tr>
<tr>
<td><code>installedApps</code></td>
<td>JSON</td>
<td>Array of tracked applications</td>
</tr>
</tbody></table>
<p><strong>Response:</strong></p>
<pre><code class="language-json">{
&quot;success&quot;: true,
&quot;message&quot;: &quot;Installed apps updated&quot;,
&quot;appsUpdated&quot;: 3
}</code></pre>
<hr>
<h4 id="updatewinrmstatus">updateWinRMStatus</h4>
<p>Updates the WinRM enabled status for a PC.</p>
<p><strong>Request:</strong></p>
<pre><code>POST /api.asp
Content-Type: application/x-www-form-urlencoded
action=updateWinRMStatus
&amp;hostname=G1ZTNCX3ESF
&amp;hasWinRM=1</code></pre>
<p><strong>Parameters:</strong></p>
<table>
<thead><tr>
<th>Parameter</th>
<th>Type</th>
<th>Description</th>
</tr></thead>
<tbody>
<tr>
<td><code>hostname</code></td>
<td>string</td>
<td>PC hostname</td>
</tr>
<tr>
<td><code>hasWinRM</code></td>
<td>int</td>
<td>WinRM status (0=disabled, 1=enabled)</td>
</tr>
</tbody></table>
<p><strong>Response:</strong></p>
<pre><code class="language-json">{
&quot;success&quot;: true,
&quot;message&quot;: &quot;WinRM status updated&quot;,
&quot;hostname&quot;: &quot;G1ZTNCX3ESF&quot;,
&quot;iswinrm&quot;: 1
}</code></pre>
<hr>
<h4 id="updatemachinepositions">updateMachinePositions</h4>
<p>Bulk update machine positions on the floor map.</p>
<p><strong>Request:</strong></p>
<pre><code>POST /api.asp
Content-Type: application/x-www-form-urlencoded
action=updateMachinePositions
&amp;changes=[{&quot;machineid&quot;:1234,&quot;mapleft&quot;:100,&quot;maptop&quot;:200}]</code></pre>
<p><strong>Parameters:</strong></p>
<table>
<thead><tr>
<th>Parameter</th>
<th>Type</th>
<th>Description</th>
</tr></thead>
<tbody>
<tr>
<td><code>changes</code></td>
<td>JSON</td>
<td>Array of position updates</td>
</tr>
</tbody></table>
<p><strong>Response:</strong></p>
<pre><code class="language-json">{
&quot;success&quot;: true,
&quot;updated&quot;: 5
}</code></pre>
<hr>
<h2 id="response-format">Response Format</h2>
<p>All responses are JSON with consistent structure:</p>
<p><strong>Success Response:</strong></p>
<pre><code class="language-json">{
&quot;success&quot;: true,
&quot;message&quot;: &quot;Operation completed&quot;,
&quot;data&quot;: [...]
}</code></pre>
<p><strong>Error Response:</strong></p>
<pre><code class="language-json">{
&quot;success&quot;: false,
&quot;error&quot;: &quot;Error description&quot;
}</code></pre>
<hr>
<h2 id="error-handling">Error Handling</h2>
<table>
<thead><tr>
<th>Error</th>
<th>Cause</th>
<th>Solution</th>
</tr></thead>
<tbody>
<tr>
<td><code>hostname and serialNumber are required</code></td>
<td>Missing required fields</td>
<td>Include all required parameters</td>
</tr>
<tr>
<td><code>PC not found: hostname</code></td>
<td>Hostname not in database</td>
<td>Verify hostname or run initial collection</td>
</tr>
<tr>
<td><code>Printer not found: printerFQDN</code></td>
<td>Printer not in database</td>
<td>Add printer to ShopDB first</td>
</tr>
<tr>
<td><code>Invalid action: xyz</code></td>
<td>Unknown action parameter</td>
<td>Check action spelling</td>
</tr>
<tr>
<td><code>Database error: ...</code></td>
<td>MySQL error</td>
<td>Check database connectivity</td>
</tr>
</tbody></table>
<hr>
<h2 id="powershell-integration">PowerShell Integration</h2>
<h3 id="sending-data-to-api">Sending Data to API</h3>
<pre><code class="language-powershell"># Build POST body
$body = @{
action = &quot;updateCompleteAsset&quot;
hostname = $env:COMPUTERNAME
serialNumber = (Get-CimInstance Win32_BIOS).SerialNumber
manufacturer = (Get-CimInstance Win32_ComputerSystem).Manufacturer
model = (Get-CimInstance Win32_ComputerSystem).Model
pcType = &quot;Shopfloor&quot;
}
# Send to API
$response = Invoke-RestMethod -Uri &quot;https://server/shopdb/api.asp&quot; -Method POST -Body $body</code></pre>
<h3 id="retrieving-pc-list">Retrieving PC List</h3>
<pre><code class="language-powershell"># Get all shopfloor PCs
$response = Invoke-RestMethod -Uri &quot;https://server/shopdb/api.asp?action=getShopfloorPCs&quot;
$pcs = $response.data
# Get CMM PCs only
$response = Invoke-RestMethod -Uri &quot;https://server/shopdb/api.asp?action=getShopfloorPCs&amp;pctypeid=2&quot;
# Get high uptime PCs
$response = Invoke-RestMethod -Uri &quot;https://server/shopdb/api.asp?action=getHighUptimePCs&amp;minUptime=30&quot;</code></pre>
<h3 id="script-usage-examples">Script Usage Examples</h3>
<pre><code class="language-powershell"># Update-ShopfloorPCs-Remote.ps1 uses getShopfloorPCs
.\Update-ShopfloorPCs-Remote.ps1 -All -Credential $cred
# Internally calls: GET /api.asp?action=getShopfloorPCs
# Reboot mode uses getHighUptimePCs
.\Update-ShopfloorPCs-Remote.ps1 -Reboot -MinUptimeDays 30
# Internally calls: GET /api.asp?action=getHighUptimePCs&amp;minUptime=30
# Invoke-RemoteMaintenance.ps1 filters by PC type
.\Invoke-RemoteMaintenance.ps1 -PcType CMM -Task DiskCleanup
# Internally calls: GET /api.asp?action=getShopfloorPCs&amp;pctypeid=2</code></pre>
<hr>
<h2 id="database-schema-reference">Database Schema Reference</h2>
<p>The API interacts with these primary tables:</p>
<table>
<thead><tr>
<th>Table</th>
<th>Purpose</th>
</tr></thead>
<tbody>
<tr>
<td><code>machines</code></td>
<td>All PCs and equipment (pctypeid IS NOT NULL for PCs)</td>
</tr>
<tr>
<td><code>communications</code></td>
<td>Network interfaces (IP, MAC, gateway)</td>
</tr>
<tr>
<td><code>dncconfig</code></td>
<td>DNC/FTP configurations</td>
</tr>
<tr>
<td><code>commconfig</code></td>
<td>Communication port settings</td>
</tr>
<tr>
<td><code>installedapps</code></td>
<td>Application tracking</td>
</tr>
<tr>
<td><code>pctype</code></td>
<td>PC type definitions</td>
</tr>
<tr>
<td><code>businessunits</code></td>
<td>Business unit definitions</td>
</tr>
<tr>
<td><code>printers</code></td>
<td>Printer inventory</td>
</tr>
</tbody></table>
<p><strong>PC Identification:</strong></p>
<ul>
<li>PCs have <code>machinetypeid IN (33, 34, 35)</code></li>
<li>PCs have <code>pctypeid IS NOT NULL</code></li>
<li>Primary network is <code>isprimary = 1</code> in communications table</li>
</ul>
</body>
</html>

586
docs/ShopDB-API.md Normal file
View File

@@ -0,0 +1,586 @@
# ShopDB API Reference
REST API for PowerShell data collection scripts and ShopDB integrations.
## Table of Contents
- [Overview](#overview)
- [Base URL](#base-url)
- [Authentication](#authentication)
- [Endpoints](#endpoints)
- [GET Endpoints](#get-endpoints)
- [POST Endpoints](#post-endpoints)
- [Response Format](#response-format)
- [Error Handling](#error-handling)
- [PowerShell Integration](#powershell-integration)
---
## Overview
The ShopDB API (`api.asp`) provides endpoints for:
- **Data Collection**: Receive PC asset data from PowerShell scripts
- **PC Retrieval**: Query lists of shopfloor PCs for remote management
- **Maintenance**: Update WinRM status, printer mappings, installed applications
- **Dashboard**: Health checks and monitoring data
**Technology**: Classic ASP (VBScript) with MySQL database
---
## Base URL
| Environment | URL |
|-------------|-----|
| Production | `https://tsgwp00525.rd.ds.ge.com/shopdb/api.asp` |
| Development | `http://192.168.122.151:8080/api.asp` |
---
## Authentication
Currently no authentication required. API is accessible from internal network only.
---
## Endpoints
### GET Endpoints
#### getDashboardData
Health check endpoint to verify API is online.
**Request:**
```
GET /api.asp?action=getDashboardData
```
**Response:**
```json
{
"success": true,
"message": "ShopDB API is online - v13 (inlined all queries)",
"version": "1.0",
"schema": "Phase 2",
"connStatus": "objConn is Open"
}
```
**Used By:** Health monitoring, connectivity tests
---
#### getShopfloorPCs
Returns list of all active shopfloor PCs for remote management operations.
**Request:**
```
GET /api.asp?action=getShopfloorPCs
GET /api.asp?action=getShopfloorPCs&pctypeid=1
GET /api.asp?action=getShopfloorPCs&businessunitid=2
```
**Query Parameters:**
| Parameter | Type | Description |
|-----------|------|-------------|
| `pctypeid` | int | Filter by PC type (optional) |
| `businessunitid` | int | Filter by business unit (optional) |
**PC Type IDs:**
| ID | Type |
|----|------|
| 1 | Shopfloor |
| 2 | CMM |
| 3 | Wax Trace |
| 4 | Keyence |
| 5 | EAS1000 |
| 6 | Genspect |
| 7 | Heat Treat |
| 8 | Engineer |
| 9 | Standard |
| 10 | Inspection |
| 11 | Dashboard |
| 12 | Lobby Display |
**Response:**
```json
{
"success": true,
"count": 45,
"data": [
{
"machineid": 1234,
"hostname": "G1ZTNCX3ESF",
"machinenumber": "M0612, M0613",
"serialnumber": "ABC1234567",
"ipaddress": "10.134.50.101",
"loggedinuser": "DOMAIN\\jsmith",
"pctype": "Shopfloor",
"pctypeid": 1,
"businessunit": "Rotor",
"businessunitid": 2,
"lastupdated": "1/15/2025 8:30 AM"
}
]
}
```
**Notes:**
- Returns only PCs with 10.134.*.* IP addresses by default
- Dashboard (11) and Lobby Display (12) types bypass IP filter
- Only includes machinetypeid 33-35 (actual PCs)
**Used By:** `Update-ShopfloorPCs-Remote.ps1 -All`, `Invoke-RemoteMaintenance.ps1 -All`
---
#### getHighUptimePCs
Returns PCs that haven't been rebooted in specified number of days.
**Request:**
```
GET /api.asp?action=getHighUptimePCs&minUptime=30
```
**Query Parameters:**
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `minUptime` | int | 10 | Minimum uptime in days |
**Response:**
```json
{
"success": true,
"count": 5,
"minUptime": 30,
"data": [
{
"machineid": 1234,
"hostname": "SHOPFLOOR-01",
"machinenumber": "M0612",
"serialnumber": "ABC1234567",
"ipaddress": "10.134.50.101",
"loggedinuser": "DOMAIN\\jsmith",
"pctype": "Shopfloor",
"uptime_days": 45,
"lastboottime": "2024-12-01 08:00:00",
"pctypeid": 1,
"businessunit": "Rotor",
"businessunitid": 2,
"lastupdated": "1/15/2025 8:30 AM"
}
]
}
```
**Used By:** `Update-ShopfloorPCs-Remote.ps1 -Reboot -MinUptimeDays 30`
---
#### getRecordedIP
Get the recorded IP address for a specific hostname.
**Request:**
```
GET /api.asp?action=getRecordedIP&hostname=G1ZTNCX3ESF
```
**Query Parameters:**
| Parameter | Type | Description |
|-----------|------|-------------|
| `hostname` | string | Computer name to look up |
**Response:**
```json
{
"success": true,
"hostname": "G1ZTNCX3ESF",
"ipaddress": "10.134.50.101"
}
```
---
#### getPCMachineRelationships
Returns PCs that have relationships to equipment (machines).
**Request:**
```
GET /api.asp?action=getPCMachineRelationships
```
**Response:**
```json
{
"success": true,
"count": 25,
"data": [
{
"pc_machineid": 1234,
"pc_hostname": "G1ZTNCX3ESF",
"equipment_machineid": 5678,
"equipment_machinenumber": "M0612"
}
]
}
```
---
### POST Endpoints
#### updateCompleteAsset
Main endpoint for PC data collection. Receives comprehensive asset data from PowerShell scripts.
**Request:**
```
POST /api.asp
Content-Type: application/x-www-form-urlencoded
action=updateCompleteAsset
&hostname=G1ZTNCX3ESF
&serialNumber=ABC1234567
&manufacturer=Dell Inc.
&model=OptiPlex 7080
&pcType=Shopfloor
&loggedInUser=DOMAIN\jsmith
&machineNo=M0612
&osVersion=Microsoft Windows 10 Enterprise
&lastBootTime=2025-01-15 08:30:00
&hasVnc=1
&hasWinRM=1
&networkInterfaces=[...]
&dncConfig=[...]
&installedApps=[...]
```
**Required Parameters:**
| Parameter | Type | Description |
|-----------|------|-------------|
| `hostname` | string | Computer name |
| `serialNumber` | string | BIOS serial number |
**Optional Parameters:**
| Parameter | Type | Description |
|-----------|------|-------------|
| `manufacturer` | string | System manufacturer |
| `model` | string | System model |
| `pcType` | string | PC classification (Shopfloor, CMM, etc.) |
| `loggedInUser` | string | Currently logged in user |
| `machineNo` | string | Associated machine number(s) |
| `osVersion` | string | Windows version |
| `lastBootTime` | datetime | Last boot timestamp |
| `hasVnc` | int | VNC installed (0/1) |
| `hasWinRM` | int | WinRM enabled (0/1) |
| `networkInterfaces` | JSON | Network adapter configurations |
| `dncConfig` | JSON | DNC/FTP settings |
| `installedApps` | JSON | Tracked applications |
| `warrantyEndDate` | date | Dell warranty expiration |
| `warrantyStatus` | string | Warranty status text |
| `dncDualPathEnabled` | int | Dual path enabled (0/1) |
| `dncPath1Name` | string | Path 1 name |
| `dncPath2Name` | string | Path 2 name |
**Network Interfaces JSON Format:**
```json
[
{
"interfaceName": "Ethernet0",
"ipAddress": "10.134.50.101",
"subnetMask": "24",
"defaultGateway": "10.134.50.1",
"macAddress": "00-11-22-33-44-55",
"isDhcp": 0,
"isActive": 1,
"isMachineNetwork": 0,
"isPrimary": 1
}
]
```
**DNC Config JSON Format:**
```json
{
"site": "WJF",
"cnc": "FANUC",
"ncif": "FOCAS2",
"machineNo": "M0612",
"ftpPrimary": "10.134.50.10",
"ftpSecondary": "10.134.50.11"
}
```
**Installed Apps JSON Format:**
```json
[
{
"appid": 5,
"appname": "PC-DMIS",
"version": "2023.1",
"isactive": 1
}
]
```
**Response:**
```json
{
"success": true,
"message": "PC data stored successfully",
"pcid": 1234,
"hostname": "G1ZTNCX3ESF",
"debugMsg": "PCType=Shopfloor, DNC=YES, Net=YES"
}
```
**Used By:** `Update-ShopfloorPCs-Remote.ps1`, `Update-PC-CompleteAsset.ps1`
---
#### updatePrinterMapping
Links a PC to its default printer.
**Request:**
```
POST /api.asp
Content-Type: application/x-www-form-urlencoded
action=updatePrinterMapping
&hostname=G1ZTNCX3ESF
&printerFQDN=printer01.domain.com
```
**Parameters:**
| Parameter | Type | Description |
|-----------|------|-------------|
| `hostname` | string | PC hostname |
| `printerFQDN` | string | Printer FQDN, Windows name, or IP |
**Response:**
```json
{
"success": true,
"message": "Printer mapping updated",
"printerId": 45,
"machinesUpdated": 1,
"matchMethod": "fqdn"
}
```
**Match Methods:** `fqdn`, `windowsname`, `ip`
---
#### updateInstalledApps
Updates the list of tracked applications installed on a PC.
**Request:**
```
POST /api.asp
Content-Type: application/x-www-form-urlencoded
action=updateInstalledApps
&hostname=G1ZTNCX3ESF
&installedApps=[{"appid":5,"appname":"PC-DMIS","version":"2023.1","isactive":1}]
```
**Parameters:**
| Parameter | Type | Description |
|-----------|------|-------------|
| `hostname` | string | PC hostname |
| `installedApps` | JSON | Array of tracked applications |
**Response:**
```json
{
"success": true,
"message": "Installed apps updated",
"appsUpdated": 3
}
```
---
#### updateWinRMStatus
Updates the WinRM enabled status for a PC.
**Request:**
```
POST /api.asp
Content-Type: application/x-www-form-urlencoded
action=updateWinRMStatus
&hostname=G1ZTNCX3ESF
&hasWinRM=1
```
**Parameters:**
| Parameter | Type | Description |
|-----------|------|-------------|
| `hostname` | string | PC hostname |
| `hasWinRM` | int | WinRM status (0=disabled, 1=enabled) |
**Response:**
```json
{
"success": true,
"message": "WinRM status updated",
"hostname": "G1ZTNCX3ESF",
"iswinrm": 1
}
```
---
#### updateMachinePositions
Bulk update machine positions on the floor map.
**Request:**
```
POST /api.asp
Content-Type: application/x-www-form-urlencoded
action=updateMachinePositions
&changes=[{"machineid":1234,"mapleft":100,"maptop":200}]
```
**Parameters:**
| Parameter | Type | Description |
|-----------|------|-------------|
| `changes` | JSON | Array of position updates |
**Response:**
```json
{
"success": true,
"updated": 5
}
```
---
## Response Format
All responses are JSON with consistent structure:
**Success Response:**
```json
{
"success": true,
"message": "Operation completed",
"data": [...]
}
```
**Error Response:**
```json
{
"success": false,
"error": "Error description"
}
```
---
## Error Handling
| Error | Cause | Solution |
|-------|-------|----------|
| `hostname and serialNumber are required` | Missing required fields | Include all required parameters |
| `PC not found: hostname` | Hostname not in database | Verify hostname or run initial collection |
| `Printer not found: printerFQDN` | Printer not in database | Add printer to ShopDB first |
| `Invalid action: xyz` | Unknown action parameter | Check action spelling |
| `Database error: ...` | MySQL error | Check database connectivity |
---
## PowerShell Integration
### Sending Data to API
```powershell
# Build POST body
$body = @{
action = "updateCompleteAsset"
hostname = $env:COMPUTERNAME
serialNumber = (Get-CimInstance Win32_BIOS).SerialNumber
manufacturer = (Get-CimInstance Win32_ComputerSystem).Manufacturer
model = (Get-CimInstance Win32_ComputerSystem).Model
pcType = "Shopfloor"
}
# Send to API
$response = Invoke-RestMethod -Uri "https://server/shopdb/api.asp" -Method POST -Body $body
```
### Retrieving PC List
```powershell
# Get all shopfloor PCs
$response = Invoke-RestMethod -Uri "https://server/shopdb/api.asp?action=getShopfloorPCs"
$pcs = $response.data
# Get CMM PCs only
$response = Invoke-RestMethod -Uri "https://server/shopdb/api.asp?action=getShopfloorPCs&pctypeid=2"
# Get high uptime PCs
$response = Invoke-RestMethod -Uri "https://server/shopdb/api.asp?action=getHighUptimePCs&minUptime=30"
```
### Script Usage Examples
```powershell
# Update-ShopfloorPCs-Remote.ps1 uses getShopfloorPCs
.\Update-ShopfloorPCs-Remote.ps1 -All -Credential $cred
# Internally calls: GET /api.asp?action=getShopfloorPCs
# Reboot mode uses getHighUptimePCs
.\Update-ShopfloorPCs-Remote.ps1 -Reboot -MinUptimeDays 30
# Internally calls: GET /api.asp?action=getHighUptimePCs&minUptime=30
# Invoke-RemoteMaintenance.ps1 filters by PC type
.\Invoke-RemoteMaintenance.ps1 -PcType CMM -Task DiskCleanup
# Internally calls: GET /api.asp?action=getShopfloorPCs&pctypeid=2
```
---
## Database Schema Reference
The API interacts with these primary tables:
| Table | Purpose |
|-------|---------|
| `machines` | All PCs and equipment (pctypeid IS NOT NULL for PCs) |
| `communications` | Network interfaces (IP, MAC, gateway) |
| `dncconfig` | DNC/FTP configurations |
| `commconfig` | Communication port settings |
| `installedapps` | Application tracking |
| `pctype` | PC type definitions |
| `businessunits` | Business unit definitions |
| `printers` | Printer inventory |
**PC Identification:**
- PCs have `machinetypeid IN (33, 34, 35)`
- PCs have `pctypeid IS NOT NULL`
- Primary network is `isprimary = 1` in communications table

View File

@@ -0,0 +1,982 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Update-PC-CompleteAsset.ps1</title>
<style>
* {
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
line-height: 1.6;
max-width: 900px;
margin: 0 auto;
padding: 20px 40px;
background-color: #ffffff;
color: #333;
}
h1 {
color: #1a5276;
border-bottom: 3px solid #1a5276;
padding-bottom: 10px;
margin-top: 0;
}
h2 {
color: #2874a6;
border-bottom: 2px solid #d5dbdb;
padding-bottom: 8px;
margin-top: 40px;
}
h3 {
color: #2e86ab;
margin-top: 30px;
}
h4 {
color: #5d6d7e;
margin-top: 25px;
}
a {
color: #2980b9;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
code {
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
background-color: #f4f4f4;
padding: 2px 6px;
border-radius: 3px;
font-size: 0.9em;
border: 1px solid #e1e1e1;
}
pre {
background-color: #2d2d2d;
color: #f8f8f2;
padding: 15px 20px;
border-radius: 6px;
overflow-x: auto;
font-family: 'Cascadia Mono', 'JetBrains Mono', 'Fira Code', 'Source Code Pro', 'DejaVu Sans Mono', 'Consolas', 'Monaco', 'Courier New', monospace;
font-size: 14px;
line-height: 1.4;
border: 1px solid #444;
margin: 15px 0;
-webkit-font-feature-settings: "liga" 0;
font-feature-settings: "liga" 0;
letter-spacing: 0;
}
pre code {
background-color: transparent;
padding: 0;
border: none;
color: inherit;
font-size: inherit;
}
table {
border-collapse: collapse;
width: 100%;
margin: 15px 0;
font-size: 14px;
}
th, td {
border: 1px solid #ddd;
padding: 10px 12px;
text-align: left;
}
th {
background-color: #34495e;
color: white;
font-weight: 600;
}
tr:nth-child(even) {
background-color: #f9f9f9;
}
tr:hover {
background-color: #f1f1f1;
}
ul, ol {
padding-left: 25px;
}
li {
margin-bottom: 5px;
}
blockquote {
border-left: 4px solid #3498db;
margin: 15px 0;
padding: 10px 20px;
background-color: #f8f9fa;
color: #555;
}
hr {
border: none;
border-top: 2px solid #eee;
margin: 30px 0;
}
.toc {
background-color: #f8f9fa;
border: 1px solid #e9ecef;
border-radius: 6px;
padding: 20px;
margin-bottom: 30px;
}
.toc h2 {
margin-top: 0;
border-bottom: none;
font-size: 1.2em;
}
.toc ul {
list-style-type: none;
padding-left: 0;
}
.toc li {
margin-bottom: 8px;
}
.toc a {
color: #2c3e50;
}
.note {
background-color: #fff3cd;
border-left: 4px solid #ffc107;
padding: 10px 15px;
margin: 15px 0;
}
.warning {
background-color: #f8d7da;
border-left: 4px solid #dc3545;
padding: 10px 15px;
margin: 15px 0;
}
@media print {
body {
max-width: 100%;
padding: 20px;
}
pre {
white-space: pre-wrap;
word-wrap: break-word;
}
h2 {
page-break-before: auto;
}
pre, table {
page-break-inside: avoid;
}
}
</style>
</head>
<body>
<h1 id="update-pc-completeassetps1">Update-PC-CompleteAsset.ps1</h1>
<p>Local data collection script that runs directly on shopfloor PCs to collect comprehensive system information and send it to the ShopDB database.</p>
<h2 id="table-of-contents">Table of Contents</h2>
<ul>
<li><a href="#overview">Overview</a></li>
<li><a href="#api-integration">API Integration</a></li>
<li><a href="#prerequisites">Prerequisites</a></li>
<li><a href="#quick-start">Quick Start</a></li>
<li><a href="#parameters-reference">Parameters Reference</a></li>
<li><a href="#how-to-guides">How-To Guides</a></li>
<li><a href="#how-to-run-manually">Manual Execution</a></li>
<li><a href="#how-to-schedule-automatic-collection">Scheduled Tasks</a></li>
<li><a href="#how-to-deploy-via-group-policy">Group Policy Deployment</a></li>
<li><a href="#how-to-test-connectivity">Testing Connectivity</a></li>
<li><a href="#how-to-troubleshoot-issues">Troubleshooting</a></li>
<li><a href="#data-collected">Data Collected</a></li>
<li><a href="#pc-type-detection">PC Type Detection</a></li>
<li><a href="#supporting-files">Supporting Files</a></li>
<li><a href="#comparison-with-remote-script">Comparison with Remote Script</a></li>
</ul>
<hr>
<h2 id="overview">Overview</h2>
<p>This script runs locally on individual shopfloor PCs to collect comprehensive system information and send it to the ShopDB API. Unlike the remote collection script, this script runs in the local user context, allowing it to collect additional data like mapped drives and user-specific settings.</p>
<p><strong>Location:</strong> <code>S:\dt\shopfloor\scripts\complete-asset\Update-PC-CompleteAsset.ps1</code></p>
<p><strong>Use Cases:</strong></p>
<ul>
<li>Scheduled data collection on each PC</li>
<li>Startup script deployment</li>
<li>Manual inventory updates</li>
<li>Collecting data that requires local context</li>
</ul>
<p><strong>Advantages over Remote Collection:</strong></p>
<ul>
<li>Can detect V-Drive access (mapped drives)</li>
<li>Can access C:\Apps folder with user context</li>
<li>No WinRM configuration required on target</li>
<li>Works even if remote management is disabled</li>
</ul>
<hr>
<h2 id="api-integration">API Integration</h2>
<p>This script sends collected data to the ShopDB API:</p>
<h3 id="storing-pc-data">Storing PC Data</h3>
<pre><code>POST /api.asp?action=updateCompleteAsset</code></pre>
<p>Parameters include:</p>
<ul>
<li><code>hostname</code>, <code>serialNumber</code> (required)</li>
<li><code>manufacturer</code>, <code>model</code>, <code>osVersion</code></li>
<li><code>pcType</code> - Auto-detected based on installed software</li>
<li><code>networkInterfaces</code> - JSON array of network configurations</li>
<li><code>dncConfig</code> - DNC/FTP settings (if applicable)</li>
<li><code>installedApps</code> - Tracked applications with versions</li>
<li><code>hasVnc</code>, <code>hasWinRM</code> - Feature detection flags</li>
</ul>
<h3 id="updating-printer-mapping">Updating Printer Mapping</h3>
<p>If a default printer is detected:</p>
<pre><code>POST /api.asp?action=updatePrinterMapping</code></pre>
<p>Links the PC to its default network printer in ShopDB.</p>
<h3 id="updating-installed-applications">Updating Installed Applications</h3>
<pre><code>POST /api.asp?action=updateInstalledApps</code></pre>
<p>Updates the list of tracked applications (matched against <code>applications.csv</code>).</p>
<p><strong>See:</strong> <a href="ShopDB-API.html">ShopDB API Reference</a> for complete API documentation.</p>
<hr>
<h2 id="prerequisites">Prerequisites</h2>
<h3 id="on-the-target-pc">On the Target PC</h3>
<ol>
<li><strong>PowerShell 5.1 or higher</strong></li>
</ol>
<pre><code class="language-powershell"> $PSVersionTable.PSVersion</code></pre>
<ol>
<li><strong>Local administrator rights</strong> (for full data collection)</li>
</ol>
<ol>
<li><strong>Network access to ShopDB API</strong></li>
</ol>
<ul>
<li>HTTPS access to production server</li>
<li>Or HTTP access to development server</li>
</ul>
<ol>
<li><strong>TLS 1.2 support</strong> (Windows 10 has this by default)</li>
</ol>
<h3 id="script-files-required">Script Files Required</h3>
<p>The script depends on a helper file that should be in the same directory:</p>
<pre><code>complete-asset/
├── Update-PC-CompleteAsset.ps1 # Main script
├── Get-ShopfloorConfig.ps1 # Helper functions (auto-loaded)</code></pre>
<p>And the applications tracking file should be at:</p>
<pre><code>powershell/
└── applications.csv # Application definitions</code></pre>
<hr>
<h2 id="quick-start">Quick Start</h2>
<h3 id="step-1-copy-scripts-to-target-pc">Step 1: Copy Scripts to Target PC</h3>
<p>Copy the <code>complete-asset</code> folder to the target PC:</p>
<pre><code>C:\Scripts\complete-asset\
├── Update-PC-CompleteAsset.ps1
├── Get-ShopfloorConfig.ps1</code></pre>
<h3 id="step-2-open-powershell-as-administrator">Step 2: Open PowerShell as Administrator</h3>
<p>Right-click PowerShell and select "Run as administrator"</p>
<h3 id="step-3-navigate-to-script-directory">Step 3: Navigate to Script Directory</h3>
<pre><code class="language-powershell">cd C:\Scripts\complete-asset</code></pre>
<h3 id="step-4-run-the-script">Step 4: Run the Script</h3>
<pre><code class="language-powershell">.\Update-PC-CompleteAsset.ps1</code></pre>
<h3 id="step-5-verify-output">Step 5: Verify Output</h3>
<p>The script will display collection progress and API response:</p>
<pre><code>========================================
Complete PC Asset Collection &amp; Storage
========================================
Computer: SHOPFLOOR-PC01
Dashboard: https://production-server/shopdb/api.asp
=== STEP 1: COLLECT SYSTEM INFO ===
Collecting comprehensive system information...
System Details:
Hostname: SHOPFLOOR-PC01
Manufacturer: Dell Inc.
Model: OptiPlex 7080
Serial: ABC1234
PC Type: Shopfloor
...
=== STEP 4: SEND TO DATABASE ===
[OK] Complete asset data stored in database!
PCID: 1234
Operation: update</code></pre>
<hr>
<h2 id="parameters-reference">Parameters Reference</h2>
<table>
<thead><tr>
<th>Parameter</th>
<th>Type</th>
<th>Required</th>
<th>Default</th>
<th>Description</th>
</tr></thead>
<tbody>
<tr>
<td><code>-DashboardURL</code></td>
<td>string</td>
<td>No</td>
<td>Auto-detect</td>
<td>Override the API endpoint URL</td>
</tr>
<tr>
<td><code>-TestConnections</code></td>
<td>switch</td>
<td>No</td>
<td>False</td>
<td>Test connectivity only, no data collection</td>
</tr>
</tbody></table>
<hr>
<h2 id="how-to-guides">How-To Guides</h2>
<h3 id="how-to-run-manually">How to Run Manually</h3>
<h4 id="basic-execution">Basic Execution</h4>
<pre><code class="language-powershell"># Navigate to script directory
cd C:\Scripts\complete-asset
# Run with default settings (auto-detects production API)
.\Update-PC-CompleteAsset.ps1</code></pre>
<h4 id="specify-api-endpoint">Specify API Endpoint</h4>
<pre><code class="language-powershell"># Use development server
.\Update-PC-CompleteAsset.ps1 -DashboardURL &quot;http://192.168.122.151:8080/api.asp&quot;
# Use staging server
.\Update-PC-CompleteAsset.ps1 -DashboardURL &quot;https://staging-server/shopdb/api.asp&quot;</code></pre>
<h4 id="run-from-any-location">Run from Any Location</h4>
<pre><code class="language-powershell"># Full path execution
&amp; &quot;C:\Scripts\complete-asset\Update-PC-CompleteAsset.ps1&quot;
# With UNC path
&amp; &quot;\\server\share\scripts\Update-PC-CompleteAsset.ps1&quot;</code></pre>
<hr>
<h3 id="how-to-test-connectivity">How to Test Connectivity</h3>
<p>Before deploying widely, test that the PC can reach the API:</p>
<pre><code class="language-powershell">.\Update-PC-CompleteAsset.ps1 -TestConnections</code></pre>
<p><strong>Expected Output (Success):</strong></p>
<pre><code>=== CONNECTION TESTS ===
Skipping proxy test (not accessible from client PCs)
Testing dashboard connection...
Dashboard URL: https://production-server/shopdb/api.asp
[OK] Dashboard responded successfully
[OK] Dashboard connection working!</code></pre>
<p><strong>Expected Output (Failure):</strong></p>
<pre><code>=== CONNECTION TESTS ===
Testing dashboard connection...
Dashboard URL: https://production-server/shopdb/api.asp
[FAIL] Could not connect to dashboard
[FAIL] Dashboard connection failed</code></pre>
<p><strong>Troubleshooting Failed Connections:</strong></p>
<ol>
<li>Check network connectivity: <code>ping production-server</code></li>
<li>Check firewall rules for HTTPS (443)</li>
<li>Verify TLS configuration</li>
<li>Try with HTTP if HTTPS fails: <code>-DashboardURL &quot;http://...&quot;</code></li>
</ol>
<hr>
<h3 id="how-to-schedule-automatic-collection">How to Schedule Automatic Collection</h3>
<h4 id="option-1-windows-task-scheduler-gui">Option 1: Windows Task Scheduler (GUI)</h4>
<ol>
<li><strong>Open Task Scheduler</strong></li>
</ol>
<ul>
<li>Press <code>Win + R</code>, type <code>taskschd.msc</code>, press Enter</li>
</ul>
<ol>
<li><strong>Create New Task</strong></li>
</ol>
<ul>
<li>Click "Create Task" (not "Create Basic Task")</li>
</ul>
<ol>
<li><strong>General Tab</strong></li>
</ol>
<ul>
<li>Name: <code>ShopDB PC Collection</code></li>
<li>Description: <code>Collects PC data and sends to ShopDB</code></li>
<li>Security options:</li>
<li>"Run whether user is logged on or not"</li>
<li>"Run with highest privileges"</li>
<li>Configure for: Windows 10</li>
</ul>
<ol>
<li><strong>Triggers Tab</strong></li>
</ol>
<ul>
<li>New trigger: "At startup"</li>
<li>Delay task for: 5 minutes (allows network to connect)</li>
<li>Or: "Daily" at specific time</li>
</ul>
<ol>
<li><strong>Actions Tab</strong></li>
</ol>
<ul>
<li>Action: Start a program</li>
<li>Program: <code>powershell.exe</code></li>
<li>Arguments: <code>-ExecutionPolicy Bypass -WindowStyle Hidden -File &quot;C:\Scripts\complete-asset\Update-PC-CompleteAsset.ps1&quot;</code></li>
</ul>
<ol>
<li><strong>Conditions Tab</strong></li>
</ol>
<ul>
<li>Check "Start only if network connection is available"</li>
</ul>
<ol>
<li><strong>Settings Tab</strong></li>
</ol>
<ul>
<li>Allow task to be run on demand</li>
<li>Stop task if it runs longer than: 1 hour</li>
</ul>
<h4 id="option-2-powershell-script-to-create-task">Option 2: PowerShell Script to Create Task</h4>
<pre><code class="language-powershell"># Run this on target PC as administrator
$action = New-ScheduledTaskAction -Execute &quot;powershell.exe&quot; `
-Argument &#x27;-ExecutionPolicy Bypass -WindowStyle Hidden -File &quot;C:\Scripts\complete-asset\Update-PC-CompleteAsset.ps1&quot;&#x27;
$trigger = New-ScheduledTaskTrigger -AtStartup -RandomDelay (New-TimeSpan -Minutes 5)
$principal = New-ScheduledTaskPrincipal -UserId &quot;SYSTEM&quot; -LogonType ServiceAccount -RunLevel Highest
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries `
-StartWhenAvailable -ExecutionTimeLimit (New-TimeSpan -Hours 1)
Register-ScheduledTask -TaskName &quot;ShopDB PC Collection&quot; `
-Action $action -Trigger $trigger -Principal $principal -Settings $settings `
-Description &quot;Collects PC data and sends to ShopDB&quot;</code></pre>
<h4 id="option-3-daily-collection-at-specific-time">Option 3: Daily Collection at Specific Time</h4>
<pre><code class="language-powershell"># Run daily at 6:00 AM
$trigger = New-ScheduledTaskTrigger -Daily -At 6am
Register-ScheduledTask -TaskName &quot;ShopDB PC Collection&quot; `
-Action $action -Trigger $trigger -Principal $principal -Settings $settings</code></pre>
<h4 id="verify-scheduled-task">Verify Scheduled Task</h4>
<pre><code class="language-powershell"># List the task
Get-ScheduledTask -TaskName &quot;ShopDB PC Collection&quot;
# Run the task manually to test
Start-ScheduledTask -TaskName &quot;ShopDB PC Collection&quot;
# Check task history
Get-ScheduledTaskInfo -TaskName &quot;ShopDB PC Collection&quot;</code></pre>
<hr>
<h3 id="how-to-deploy-via-group-policy">How to Deploy via Group Policy</h3>
<h4 id="step-1-prepare-network-share">Step 1: Prepare Network Share</h4>
<p>Create a network share accessible to all shopfloor PCs:</p>
<pre><code>\\fileserver\shopdb-scripts\
├── complete-asset\
│ ├── Update-PC-CompleteAsset.ps1
│ └── Get-ShopfloorConfig.ps1
└── applications.csv</code></pre>
<p>Set permissions:</p>
<ul>
<li>Domain Computers: Read & Execute</li>
<li>Authenticated Users: Read & Execute</li>
</ul>
<h4 id="step-2-create-gpo">Step 2: Create GPO</h4>
<ol>
<li>Open Group Policy Management Console</li>
<li>Create new GPO: "ShopDB PC Collection"</li>
<li>Link to OU containing shopfloor PCs</li>
</ol>
<h4 id="step-3-configure-computer-startup-script">Step 3: Configure Computer Startup Script</h4>
<p>Navigate to:</p>
<pre><code>Computer Configuration &gt; Policies &gt; Windows Settings &gt; Scripts &gt; Startup</code></pre>
<p>Add PowerShell script:</p>
<ul>
<li>Script Name: <code>\\fileserver\shopdb-scripts\complete-asset\Update-PC-CompleteAsset.ps1</code></li>
</ul>
<p>Or create a batch wrapper:</p>
<p><strong>startup-collection.bat:</strong></p>
<pre><code class="language-batch">@echo off
REM Wait for network
ping -n 30 127.0.0.1 &gt; nul
REM Run collection script
powershell.exe -ExecutionPolicy Bypass -WindowStyle Hidden -File &quot;\\fileserver\shopdb-scripts\complete-asset\Update-PC-CompleteAsset.ps1&quot;</code></pre>
<h4 id="step-4-force-gpo-update-testing">Step 4: Force GPO Update (Testing)</h4>
<p>On target PC:</p>
<pre><code class="language-cmd">gpupdate /force</code></pre>
<p>Then restart to trigger startup script.</p>
<hr>
<h3 id="how-to-deploy-via-sccmendpoint-manager">How to Deploy via SCCM/Endpoint Manager</h3>
<h4 id="create-application">Create Application</h4>
<ol>
<li><strong>Detection Method:</strong></li>
</ol>
<pre><code class="language-powershell"> # Detect if last collection was within 24 hours
$logPath = &quot;C:\Logs\CompleteAsset&quot;
$recentLog = Get-ChildItem $logPath -Filter &quot;*.log&quot; |
Where-Object { $_.LastWriteTime -gt (Get-Date).AddHours(-24) }
if ($recentLog) { Write-Output &quot;Installed&quot; }</code></pre>
<ol>
<li><strong>Install Command:</strong></li>
</ol>
<pre><code class="language-cmd"> powershell.exe -ExecutionPolicy Bypass -File &quot;Update-PC-CompleteAsset.ps1&quot;</code></pre>
<ol>
<li><strong>Deployment Schedule:</strong></li>
</ol>
<ul>
<li>Recurring deployment: Daily</li>
<li>Run as: System</li>
</ul>
<hr>
<h3 id="how-to-troubleshoot-issues">How to Troubleshoot Issues</h3>
<h4 id="problem-script-runs-but-no-data-in-database">Problem: Script Runs But No Data in Database</h4>
<p><strong>Check 1: API Response</strong> Look at script output for API errors:</p>
<pre><code>[FAIL] Dashboard could not store data: Invalid hostname</code></pre>
<p><strong>Check 2: Network Connectivity</strong></p>
<pre><code class="language-powershell">.\Update-PC-CompleteAsset.ps1 -TestConnections</code></pre>
<p><strong>Check 3: Log Files</strong></p>
<pre><code class="language-powershell"># Find recent log files
Get-ChildItem &quot;C:\Logs\CompleteAsset&quot; -Recurse | Sort-Object LastWriteTime -Descending | Select -First 5</code></pre>
<hr>
<h4 id="problem-pc-type-detection-wrong">Problem: PC Type Detection Wrong</h4>
<p><strong>Check installed applications:</strong></p>
<pre><code class="language-powershell"># List installed apps the script sees
Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* |
Where-Object { $_.DisplayName } |
Select-Object DisplayName |
Sort-Object DisplayName</code></pre>
<p><strong>Verify detection criteria:</strong></p>
<ul>
<li>Dashboard: Look for "GE Aerospace Dashboard"</li>
<li>CMM: Look for "PC-DMIS" or "PCDMIS" or "goCMM" or "DODA"</li>
<li>Wax Trace: Look for "FormTracePak" or "FormStatusMonitor"</li>
</ul>
<hr>
<h4 id="problem-dnc-configuration-not-detected">Problem: DNC Configuration Not Detected</h4>
<p><strong>Check registry paths:</strong></p>
<pre><code class="language-powershell"># Check 32-bit registry
Test-Path &quot;HKLM:\SOFTWARE\GE Aircraft Engines&quot;
# Check 64-bit registry
Test-Path &quot;HKLM:\SOFTWARE\WOW6432Node\GE Aircraft Engines&quot;
# List DNC settings
Get-ChildItem &quot;HKLM:\SOFTWARE\WOW6432Node\GE Aircraft Engines\DNC&quot; -Recurse</code></pre>
<hr>
<h4 id="problem-serial-ports-not-detected">Problem: Serial Ports Not Detected</h4>
<p><strong>Check Win32_SerialPort:</strong></p>
<pre><code class="language-powershell">Get-CimInstance -ClassName Win32_SerialPort | Select DeviceID, Description</code></pre>
<p>If empty, serial ports may be virtual or use different drivers.</p>
<hr>
<h4 id="problem-vnc-not-detected">Problem: VNC Not Detected</h4>
<p><strong>Check manually:</strong></p>
<pre><code class="language-powershell"># Check registry
Get-ItemProperty &quot;HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*&quot; |
Where-Object { $_.DisplayName -like &quot;*VNC*&quot; }
# Check service
Get-Service -Name &quot;vncserver*&quot;</code></pre>
<hr>
<h4 id="problem-script-errors-on-startup">Problem: Script Errors on Startup</h4>
<p><strong>Check execution policy:</strong></p>
<pre><code class="language-powershell">Get-ExecutionPolicy
# Should be RemoteSigned or Bypass
# Fix:
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope LocalMachine</code></pre>
<p><strong>Check script signing:</strong> If policy requires signed scripts, sign the script or use:</p>
<pre><code class="language-powershell">powershell.exe -ExecutionPolicy Bypass -File &quot;script.ps1&quot;</code></pre>
<hr>
<h2 id="data-collected">Data Collected</h2>
<h3 id="basic-system-information">Basic System Information</h3>
<table>
<thead><tr>
<th>Field</th>
<th>Source</th>
<th>Example</th>
</tr></thead>
<tbody>
<tr>
<td>Hostname</td>
<td><code>$env:COMPUTERNAME</code></td>
<td><code>SHOPFLOOR-PC01</code></td>
</tr>
<tr>
<td>Serial Number</td>
<td>CIM_BIOSElement</td>
<td><code>ABC1234</code></td>
</tr>
<tr>
<td>Service Tag</td>
<td>CIM_BIOSElement</td>
<td><code>ABC1234</code></td>
</tr>
<tr>
<td>Manufacturer</td>
<td>CIM_ComputerSystem</td>
<td><code>Dell Inc.</code></td>
</tr>
<tr>
<td>Model</td>
<td>CIM_ComputerSystem</td>
<td><code>OptiPlex 7080</code></td>
</tr>
<tr>
<td>Total Physical Memory</td>
<td>CIM_ComputerSystem</td>
<td><code>16.0</code> GB</td>
</tr>
<tr>
<td>Domain Role</td>
<td>CIM_ComputerSystem</td>
<td><code>1</code> (Member Workstation)</td>
</tr>
<tr>
<td>OS Version</td>
<td>CIM_OperatingSystem</td>
<td><code>Windows 10 Enterprise</code></td>
</tr>
<tr>
<td>Last Boot Time</td>
<td>CIM_OperatingSystem</td>
<td><code>2025-01-15 08:30:00</code></td>
</tr>
<tr>
<td>Current Time Zone</td>
<td>Get-TimeZone</td>
<td><code>Eastern Standard Time</code></td>
</tr>
<tr>
<td>Logged In User</td>
<td>CIM_ComputerSystem</td>
<td><code>DOMAIN\jsmith</code></td>
</tr>
<tr>
<td>PC Type</td>
<td>Software Detection</td>
<td><code>Shopfloor</code></td>
</tr>
<tr>
<td>Machine No</td>
<td>Hostname/Registry</td>
<td><code>M0612</code></td>
</tr>
</tbody></table>
<h3 id="dnc-configuration-shopfloor-pcs">DNC Configuration (Shopfloor PCs)</h3>
<table>
<thead><tr>
<th>Field</th>
<th>Registry Path</th>
<th>Example</th>
</tr></thead>
<tbody>
<tr>
<td>Site</td>
<td><code>DNC\General\Site</code></td>
<td><code>WJF</code></td>
</tr>
<tr>
<td>CNC</td>
<td><code>DNC\General\Cnc</code></td>
<td><code>FANUC</code></td>
</tr>
<tr>
<td>NcIF</td>
<td><code>DNC\General\NcIF</code></td>
<td><code>FOCAS2</code></td>
</tr>
<tr>
<td>Machine No</td>
<td><code>DNC\General\MachineNo</code></td>
<td><code>M0612</code></td>
</tr>
<tr>
<td>Host Type</td>
<td><code>DNC\General\HostType</code></td>
<td><code>MX</code></td>
</tr>
<tr>
<td>FTP Primary</td>
<td><code>DNC\MX\FtpHostPrimary</code></td>
<td><code>10.134.50.10</code></td>
</tr>
<tr>
<td>FTP Secondary</td>
<td><code>DNC\MX\FtpHostSecondary</code></td>
<td><code>10.134.50.11</code></td>
</tr>
</tbody></table>
<h3 id="ge-registry-information">GE Registry Information</h3>
<table>
<thead><tr>
<th>Field</th>
<th>Source</th>
<th>Example</th>
</tr></thead>
<tbody>
<tr>
<td>Registry 32-bit</td>
<td>Path exists check</td>
<td><code>true</code></td>
</tr>
<tr>
<td>Registry 64-bit</td>
<td>Path exists check</td>
<td><code>true</code></td>
</tr>
<tr>
<td>Dual Path Enabled</td>
<td>eFocas registry</td>
<td><code>true</code></td>
</tr>
<tr>
<td>Path 1 Name</td>
<td>eFocas registry</td>
<td><code>Primary</code></td>
</tr>
<tr>
<td>Path 2 Name</td>
<td>eFocas registry</td>
<td><code>Backup</code></td>
</tr>
</tbody></table>
<h3 id="network-interfaces">Network Interfaces</h3>
<table>
<thead><tr>
<th>Field</th>
<th>Source</th>
<th>Example</th>
</tr></thead>
<tbody>
<tr>
<td>Interface Name</td>
<td>Get-NetAdapter</td>
<td><code>Ethernet0</code></td>
</tr>
<tr>
<td>IP Address</td>
<td>Get-NetIPConfiguration</td>
<td><code>10.134.50.101</code></td>
</tr>
<tr>
<td>Subnet Mask</td>
<td>Get-NetIPConfiguration</td>
<td><code>24</code></td>
</tr>
<tr>
<td>Default Gateway</td>
<td>Get-NetIPConfiguration</td>
<td><code>10.134.50.1</code></td>
</tr>
<tr>
<td>MAC Address</td>
<td>Get-NetAdapter</td>
<td><code>00-11-22-33-44-55</code></td>
</tr>
<tr>
<td>Is DHCP</td>
<td>Get-NetIPConfiguration</td>
<td><code>false</code></td>
</tr>
<tr>
<td>Is Active</td>
<td>Get-NetAdapter</td>
<td><code>true</code></td>
</tr>
<tr>
<td>Is Machine Network</td>
<td>IP pattern match</td>
<td><code>false</code> (192.168.<em> or 100.0.0.</em> for CMM)</td>
</tr>
<tr>
<td>Is Primary</td>
<td>IP pattern match</td>
<td><code>true</code> (10.134.*)</td>
</tr>
</tbody></table>
<h3 id="additional-data">Additional Data</h3>
<table>
<thead><tr>
<th>Field</th>
<th>Source</th>
<th>Example</th>
</tr></thead>
<tbody>
<tr>
<td>Serial Ports</td>
<td>Win32_SerialPort</td>
<td><code>COM1, COM2</code></td>
</tr>
<tr>
<td>Has VNC</td>
<td>Registry + Service check</td>
<td><code>true</code></td>
</tr>
<tr>
<td>Default Printer FQDN</td>
<td>Win32_Printer</td>
<td><code>10.80.92.53</code></td>
</tr>
<tr>
<td>All Installed Apps</td>
<td>Registry (HKLM + HKU)</td>
<td>127 apps</td>
</tr>
<tr>
<td>Tracked Applications</td>
<td>CSV matching</td>
<td><code>UDC v2.1, Tanium v7.4</code></td>
</tr>
</tbody></table>
<hr>
<h2 id="pc-type-detection">PC Type Detection</h2>
<p>The script detects PC type based on installed software in this priority order:</p>
<table>
<thead><tr>
<th>Priority</th>
<th>Type</th>
<th>Detection Method</th>
</tr></thead>
<tbody>
<tr>
<td>1</td>
<td>Dashboard</td>
<td><code>GE Aerospace Dashboard</code> installed</td>
</tr>
<tr>
<td>2</td>
<td>Lobby Display</td>
<td><code>GE Aerospace Lobby Display</code> installed</td>
</tr>
<tr>
<td>3</td>
<td>CMM</td>
<td>PC-DMIS, goCMM, or DODA software</td>
</tr>
<tr>
<td>4</td>
<td>Wax Trace</td>
<td>FormTracePak or FormStatusMonitor</td>
</tr>
<tr>
<td>5</td>
<td>Keyence</td>
<td>VR-3000, VR-5000, or VR-6000</td>
</tr>
<tr>
<td>6</td>
<td>EAS1000</td>
<td>GageCal or NI Software</td>
</tr>
<tr>
<td>7</td>
<td>Genspect</td>
<td>Genspect measuring software</td>
</tr>
<tr>
<td>8</td>
<td>Heat Treat</td>
<td>HeatTreat application</td>
</tr>
<tr>
<td>9</td>
<td>Inspection</td>
<td>Machine #: 0612, 0613, 0615, 8003</td>
</tr>
<tr>
<td>10</td>
<td>Shopfloor</td>
<td>Default for domain shop PCs</td>
</tr>
<tr>
<td>11</td>
<td>Engineer</td>
<td>Has C:\Apps AND V-Drive access</td>
</tr>
<tr>
<td>12</td>
<td>Standard</td>
<td>Default for other domain PCs</td>
</tr>
</tbody></table>
<p><strong>Note:</strong> Priority matters - a PC with both Dashboard and CMM software will be classified as "Dashboard".</p>
<hr>
<h2 id="supporting-files">Supporting Files</h2>
<h3 id="required-directory-structure">Required Directory Structure</h3>
<pre><code>S:\dt\shopfloor\scripts\complete-asset\
├── Update-PC-CompleteAsset.ps1 # Main script
└── Get-ShopfloorConfig.ps1 # Helper functions (REQUIRED)</code></pre>
<p><strong>Important:</strong> Both files must be in the same directory. The main script dot-sources the helper:</p>
<pre><code class="language-powershell">. &quot;$PSScriptRoot\Get-ShopfloorConfig.ps1&quot;</code></pre>
<h3 id="get-shopfloorconfigps1">Get-ShopfloorConfig.ps1</h3>
<p>Helper script providing these functions:</p>
<table>
<thead><tr>
<th>Function</th>
<th>Purpose</th>
</tr></thead>
<tbody>
<tr>
<td><code>Get-NetworkInterfaceConfig</code></td>
<td>Network adapters with IsPrimary/IsMachineNetwork</td>
</tr>
<tr>
<td><code>Get-SerialPortConfig</code></td>
<td>DNC serial port settings</td>
</tr>
<tr>
<td><code>Get-GERegistryInfo</code></td>
<td>GE Aircraft Engines registry (DualPath, paths)</td>
</tr>
<tr>
<td><code>Get-DNCConfig</code></td>
<td>DNC general configuration</td>
</tr>
<tr>
<td><code>Get-ShopfloorConfigurations</code></td>
<td>Combines all above into one call</td>
</tr>
<tr>
<td><code>Get-InstalledApplications</code></td>
<td>Detects UDC/CLM processes</td>
</tr>
</tbody></table>
<h3 id="applicationscsv">applications.csv</h3>
<p>Defines tracked applications for version tracking:</p>
<pre><code class="language-csv">app_id,app_name,search_patterns
2,UDC,&quot;Universal Data Collector&quot;
4,CLM,&quot;Cell Level Manager|ppdcs&quot;
77,HeatTreat,&quot;HeatTreat&quot;
82,GE Aerospace Dashboard,&quot;GE Aerospace Dashboard&quot;
83,GE Aerospace Lobby Display,&quot;GE Aerospace Lobby Display&quot;</code></pre>
<p><strong>Location:</strong> <code>S:\dt\shopfloor\scripts\applications.csv</code></p>
<hr>
<h2 id="comparison-with-remote-script">Comparison with Remote Script</h2>
<table>
<thead><tr>
<th>Feature</th>
<th>Local Script</th>
<th>Remote Script</th>
</tr></thead>
<tbody>
<tr>
<td>Execution</td>
<td>On target PC</td>
<td>From admin workstation</td>
</tr>
<tr>
<td>WinRM Required</td>
<td>No</td>
<td>Yes</td>
</tr>
<tr>
<td>V-Drive Detection</td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td>C:\Apps Detection</td>
<td>Yes</td>
<td>Limited</td>
</tr>
<tr>
<td>Batch Operations</td>
<td>No (one PC)</td>
<td>Yes (many PCs)</td>
</tr>
<tr>
<td>User Context</td>
<td>Local user</td>
<td>WinRM context</td>
</tr>
<tr>
<td>Admin Rights</td>
<td>Needed locally</td>
<td>Needed remotely</td>
</tr>
</tbody></table>
</body>
</html>

View File

@@ -0,0 +1,664 @@
# Update-PC-CompleteAsset.ps1
Local data collection script that runs directly on shopfloor PCs to collect comprehensive system information and send it to the ShopDB database.
## Table of Contents
- [Overview](#overview)
- [API Integration](#api-integration)
- [Prerequisites](#prerequisites)
- [Quick Start](#quick-start)
- [Parameters Reference](#parameters-reference)
- [How-To Guides](#how-to-guides)
- [Manual Execution](#how-to-run-manually)
- [Scheduled Tasks](#how-to-schedule-automatic-collection)
- [Group Policy Deployment](#how-to-deploy-via-group-policy)
- [Testing Connectivity](#how-to-test-connectivity)
- [Troubleshooting](#how-to-troubleshoot-issues)
- [Data Collected](#data-collected)
- [PC Type Detection](#pc-type-detection)
- [Supporting Files](#supporting-files)
- [Comparison with Remote Script](#comparison-with-remote-script)
---
## Overview
This script runs locally on individual shopfloor PCs to collect comprehensive system information and send it to the ShopDB API. Unlike the remote collection script, this script runs in the local user context, allowing it to collect additional data like mapped drives and user-specific settings.
**Location:** `S:\dt\shopfloor\scripts\complete-asset\Update-PC-CompleteAsset.ps1`
**Use Cases:**
- Scheduled data collection on each PC
- Startup script deployment
- Manual inventory updates
- Collecting data that requires local context
**Advantages over Remote Collection:**
- Can detect V-Drive access (mapped drives)
- Can access C:\Apps folder with user context
- No WinRM configuration required on target
- Works even if remote management is disabled
---
## API Integration
This script sends collected data to the ShopDB API:
### Storing PC Data
```
POST /api.asp?action=updateCompleteAsset
```
Parameters include:
- `hostname`, `serialNumber` (required)
- `manufacturer`, `model`, `osVersion`
- `pcType` - Auto-detected based on installed software
- `networkInterfaces` - JSON array of network configurations
- `dncConfig` - DNC/FTP settings (if applicable)
- `installedApps` - Tracked applications with versions
- `hasVnc`, `hasWinRM` - Feature detection flags
### Updating Printer Mapping
If a default printer is detected:
```
POST /api.asp?action=updatePrinterMapping
```
Links the PC to its default network printer in ShopDB.
### Updating Installed Applications
```
POST /api.asp?action=updateInstalledApps
```
Updates the list of tracked applications (matched against `applications.csv`).
**See:** [ShopDB API Reference](ShopDB-API.html) for complete API documentation.
---
## Prerequisites
### On the Target PC
1. **PowerShell 5.1 or higher**
```powershell
$PSVersionTable.PSVersion
```
2. **Local administrator rights** (for full data collection)
3. **Network access to ShopDB API**
- HTTPS access to production server
- Or HTTP access to development server
4. **TLS 1.2 support** (Windows 10 has this by default)
### Script Files Required
The script depends on a helper file that should be in the same directory:
```
complete-asset/
├── Update-PC-CompleteAsset.ps1 # Main script
├── Get-ShopfloorConfig.ps1 # Helper functions (auto-loaded)
```
And the applications tracking file should be at:
```
powershell/
└── applications.csv # Application definitions
```
---
## Quick Start
### Step 1: Copy Scripts to Target PC
Copy the `complete-asset` folder to the target PC:
```
C:\Scripts\complete-asset\
├── Update-PC-CompleteAsset.ps1
├── Get-ShopfloorConfig.ps1
```
### Step 2: Open PowerShell as Administrator
Right-click PowerShell and select "Run as administrator"
### Step 3: Navigate to Script Directory
```powershell
cd C:\Scripts\complete-asset
```
### Step 4: Run the Script
```powershell
.\Update-PC-CompleteAsset.ps1
```
### Step 5: Verify Output
The script will display collection progress and API response:
```
========================================
Complete PC Asset Collection & Storage
========================================
Computer: SHOPFLOOR-PC01
Dashboard: https://production-server/shopdb/api.asp
=== STEP 1: COLLECT SYSTEM INFO ===
Collecting comprehensive system information...
System Details:
Hostname: SHOPFLOOR-PC01
Manufacturer: Dell Inc.
Model: OptiPlex 7080
Serial: ABC1234
PC Type: Shopfloor
...
=== STEP 4: SEND TO DATABASE ===
[OK] Complete asset data stored in database!
PCID: 1234
Operation: update
```
---
## Parameters Reference
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `-DashboardURL` | string | No | Auto-detect | Override the API endpoint URL |
| `-TestConnections` | switch | No | False | Test connectivity only, no data collection |
---
## How-To Guides
### How to Run Manually
#### Basic Execution
```powershell
# Navigate to script directory
cd C:\Scripts\complete-asset
# Run with default settings (auto-detects production API)
.\Update-PC-CompleteAsset.ps1
```
#### Specify API Endpoint
```powershell
# Use development server
.\Update-PC-CompleteAsset.ps1 -DashboardURL "http://192.168.122.151:8080/api.asp"
# Use staging server
.\Update-PC-CompleteAsset.ps1 -DashboardURL "https://staging-server/shopdb/api.asp"
```
#### Run from Any Location
```powershell
# Full path execution
& "C:\Scripts\complete-asset\Update-PC-CompleteAsset.ps1"
# With UNC path
& "\\server\share\scripts\Update-PC-CompleteAsset.ps1"
```
---
### How to Test Connectivity
Before deploying widely, test that the PC can reach the API:
```powershell
.\Update-PC-CompleteAsset.ps1 -TestConnections
```
**Expected Output (Success):**
```
=== CONNECTION TESTS ===
Skipping proxy test (not accessible from client PCs)
Testing dashboard connection...
Dashboard URL: https://production-server/shopdb/api.asp
[OK] Dashboard responded successfully
[OK] Dashboard connection working!
```
**Expected Output (Failure):**
```
=== CONNECTION TESTS ===
Testing dashboard connection...
Dashboard URL: https://production-server/shopdb/api.asp
[FAIL] Could not connect to dashboard
[FAIL] Dashboard connection failed
```
**Troubleshooting Failed Connections:**
1. Check network connectivity: `ping production-server`
2. Check firewall rules for HTTPS (443)
3. Verify TLS configuration
4. Try with HTTP if HTTPS fails: `-DashboardURL "http://..."`
---
### How to Schedule Automatic Collection
#### Option 1: Windows Task Scheduler (GUI)
1. **Open Task Scheduler**
- Press `Win + R`, type `taskschd.msc`, press Enter
2. **Create New Task**
- Click "Create Task" (not "Create Basic Task")
3. **General Tab**
- Name: `ShopDB PC Collection`
- Description: `Collects PC data and sends to ShopDB`
- Security options:
- "Run whether user is logged on or not"
- "Run with highest privileges"
- Configure for: Windows 10
4. **Triggers Tab**
- New trigger: "At startup"
- Delay task for: 5 minutes (allows network to connect)
- Or: "Daily" at specific time
5. **Actions Tab**
- Action: Start a program
- Program: `powershell.exe`
- Arguments: `-ExecutionPolicy Bypass -WindowStyle Hidden -File "C:\Scripts\complete-asset\Update-PC-CompleteAsset.ps1"`
6. **Conditions Tab**
- Check "Start only if network connection is available"
7. **Settings Tab**
- Allow task to be run on demand
- Stop task if it runs longer than: 1 hour
#### Option 2: PowerShell Script to Create Task
```powershell
# Run this on target PC as administrator
$action = New-ScheduledTaskAction -Execute "powershell.exe" `
-Argument '-ExecutionPolicy Bypass -WindowStyle Hidden -File "C:\Scripts\complete-asset\Update-PC-CompleteAsset.ps1"'
$trigger = New-ScheduledTaskTrigger -AtStartup -RandomDelay (New-TimeSpan -Minutes 5)
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries `
-StartWhenAvailable -ExecutionTimeLimit (New-TimeSpan -Hours 1)
Register-ScheduledTask -TaskName "ShopDB PC Collection" `
-Action $action -Trigger $trigger -Principal $principal -Settings $settings `
-Description "Collects PC data and sends to ShopDB"
```
#### Option 3: Daily Collection at Specific Time
```powershell
# Run daily at 6:00 AM
$trigger = New-ScheduledTaskTrigger -Daily -At 6am
Register-ScheduledTask -TaskName "ShopDB PC Collection" `
-Action $action -Trigger $trigger -Principal $principal -Settings $settings
```
#### Verify Scheduled Task
```powershell
# List the task
Get-ScheduledTask -TaskName "ShopDB PC Collection"
# Run the task manually to test
Start-ScheduledTask -TaskName "ShopDB PC Collection"
# Check task history
Get-ScheduledTaskInfo -TaskName "ShopDB PC Collection"
```
---
### How to Deploy via Group Policy
#### Step 1: Prepare Network Share
Create a network share accessible to all shopfloor PCs:
```
\\fileserver\shopdb-scripts\
├── complete-asset\
│ ├── Update-PC-CompleteAsset.ps1
│ └── Get-ShopfloorConfig.ps1
└── applications.csv
```
Set permissions:
- Domain Computers: Read & Execute
- Authenticated Users: Read & Execute
#### Step 2: Create GPO
1. Open Group Policy Management Console
2. Create new GPO: "ShopDB PC Collection"
3. Link to OU containing shopfloor PCs
#### Step 3: Configure Computer Startup Script
Navigate to:
```
Computer Configuration > Policies > Windows Settings > Scripts > Startup
```
Add PowerShell script:
- Script Name: `\\fileserver\shopdb-scripts\complete-asset\Update-PC-CompleteAsset.ps1`
Or create a batch wrapper:
**startup-collection.bat:**
```batch
@echo off
REM Wait for network
ping -n 30 127.0.0.1 > nul
REM Run collection script
powershell.exe -ExecutionPolicy Bypass -WindowStyle Hidden -File "\\fileserver\shopdb-scripts\complete-asset\Update-PC-CompleteAsset.ps1"
```
#### Step 4: Force GPO Update (Testing)
On target PC:
```cmd
gpupdate /force
```
Then restart to trigger startup script.
---
### How to Deploy via SCCM/Endpoint Manager
#### Create Application
1. **Detection Method:**
```powershell
# Detect if last collection was within 24 hours
$logPath = "C:\Logs\CompleteAsset"
$recentLog = Get-ChildItem $logPath -Filter "*.log" |
Where-Object { $_.LastWriteTime -gt (Get-Date).AddHours(-24) }
if ($recentLog) { Write-Output "Installed" }
```
2. **Install Command:**
```cmd
powershell.exe -ExecutionPolicy Bypass -File "Update-PC-CompleteAsset.ps1"
```
3. **Deployment Schedule:**
- Recurring deployment: Daily
- Run as: System
---
### How to Troubleshoot Issues
#### Problem: Script Runs But No Data in Database
**Check 1: API Response**
Look at script output for API errors:
```
[FAIL] Dashboard could not store data: Invalid hostname
```
**Check 2: Network Connectivity**
```powershell
.\Update-PC-CompleteAsset.ps1 -TestConnections
```
**Check 3: Log Files**
```powershell
# Find recent log files
Get-ChildItem "C:\Logs\CompleteAsset" -Recurse | Sort-Object LastWriteTime -Descending | Select -First 5
```
---
#### Problem: PC Type Detection Wrong
**Check installed applications:**
```powershell
# List installed apps the script sees
Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* |
Where-Object { $_.DisplayName } |
Select-Object DisplayName |
Sort-Object DisplayName
```
**Verify detection criteria:**
- Dashboard: Look for "GE Aerospace Dashboard"
- CMM: Look for "PC-DMIS" or "PCDMIS" or "goCMM" or "DODA"
- Wax Trace: Look for "FormTracePak" or "FormStatusMonitor"
---
#### Problem: DNC Configuration Not Detected
**Check registry paths:**
```powershell
# Check 32-bit registry
Test-Path "HKLM:\SOFTWARE\GE Aircraft Engines"
# Check 64-bit registry
Test-Path "HKLM:\SOFTWARE\WOW6432Node\GE Aircraft Engines"
# List DNC settings
Get-ChildItem "HKLM:\SOFTWARE\WOW6432Node\GE Aircraft Engines\DNC" -Recurse
```
---
#### Problem: Serial Ports Not Detected
**Check Win32_SerialPort:**
```powershell
Get-CimInstance -ClassName Win32_SerialPort | Select DeviceID, Description
```
If empty, serial ports may be virtual or use different drivers.
---
#### Problem: VNC Not Detected
**Check manually:**
```powershell
# Check registry
Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*" |
Where-Object { $_.DisplayName -like "*VNC*" }
# Check service
Get-Service -Name "vncserver*"
```
---
#### Problem: Script Errors on Startup
**Check execution policy:**
```powershell
Get-ExecutionPolicy
# Should be RemoteSigned or Bypass
# Fix:
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope LocalMachine
```
**Check script signing:**
If policy requires signed scripts, sign the script or use:
```powershell
powershell.exe -ExecutionPolicy Bypass -File "script.ps1"
```
---
## Data Collected
### Basic System Information
| Field | Source | Example |
|-------|--------|---------|
| Hostname | `$env:COMPUTERNAME` | `SHOPFLOOR-PC01` |
| Serial Number | CIM_BIOSElement | `ABC1234` |
| Service Tag | CIM_BIOSElement | `ABC1234` |
| Manufacturer | CIM_ComputerSystem | `Dell Inc.` |
| Model | CIM_ComputerSystem | `OptiPlex 7080` |
| Total Physical Memory | CIM_ComputerSystem | `16.0` GB |
| Domain Role | CIM_ComputerSystem | `1` (Member Workstation) |
| OS Version | CIM_OperatingSystem | `Windows 10 Enterprise` |
| Last Boot Time | CIM_OperatingSystem | `2025-01-15 08:30:00` |
| Current Time Zone | Get-TimeZone | `Eastern Standard Time` |
| Logged In User | CIM_ComputerSystem | `DOMAIN\jsmith` |
| PC Type | Software Detection | `Shopfloor` |
| Machine No | Hostname/Registry | `M0612` |
### DNC Configuration (Shopfloor PCs)
| Field | Registry Path | Example |
|-------|---------------|---------|
| Site | `DNC\General\Site` | `WJF` |
| CNC | `DNC\General\Cnc` | `FANUC` |
| NcIF | `DNC\General\NcIF` | `FOCAS2` |
| Machine No | `DNC\General\MachineNo` | `M0612` |
| Host Type | `DNC\General\HostType` | `MX` |
| FTP Primary | `DNC\MX\FtpHostPrimary` | `10.134.50.10` |
| FTP Secondary | `DNC\MX\FtpHostSecondary` | `10.134.50.11` |
### GE Registry Information
| Field | Source | Example |
|-------|--------|---------|
| Registry 32-bit | Path exists check | `true` |
| Registry 64-bit | Path exists check | `true` |
| Dual Path Enabled | eFocas registry | `true` |
| Path 1 Name | eFocas registry | `Primary` |
| Path 2 Name | eFocas registry | `Backup` |
### Network Interfaces
| Field | Source | Example |
|-------|--------|---------|
| Interface Name | Get-NetAdapter | `Ethernet0` |
| IP Address | Get-NetIPConfiguration | `10.134.50.101` |
| Subnet Mask | Get-NetIPConfiguration | `24` |
| Default Gateway | Get-NetIPConfiguration | `10.134.50.1` |
| MAC Address | Get-NetAdapter | `00-11-22-33-44-55` |
| Is DHCP | Get-NetIPConfiguration | `false` |
| Is Active | Get-NetAdapter | `true` |
| Is Machine Network | IP pattern match | `false` (192.168.* or 100.0.0.* for CMM) |
| Is Primary | IP pattern match | `true` (10.134.*) |
### Additional Data
| Field | Source | Example |
|-------|--------|---------|
| Serial Ports | Win32_SerialPort | `COM1, COM2` |
| Has VNC | Registry + Service check | `true` |
| Default Printer FQDN | Win32_Printer | `10.80.92.53` |
| All Installed Apps | Registry (HKLM + HKU) | 127 apps |
| Tracked Applications | CSV matching | `UDC v2.1, Tanium v7.4` |
---
## PC Type Detection
The script detects PC type based on installed software in this priority order:
| Priority | Type | Detection Method |
|----------|------|-----------------|
| 1 | Dashboard | `GE Aerospace Dashboard` installed |
| 2 | Lobby Display | `GE Aerospace Lobby Display` installed |
| 3 | CMM | PC-DMIS, goCMM, or DODA software |
| 4 | Wax Trace | FormTracePak or FormStatusMonitor |
| 5 | Keyence | VR-3000, VR-5000, or VR-6000 |
| 6 | EAS1000 | GageCal or NI Software |
| 7 | Genspect | Genspect measuring software |
| 8 | Heat Treat | HeatTreat application |
| 9 | Inspection | Machine #: 0612, 0613, 0615, 8003 |
| 10 | Shopfloor | Default for domain shop PCs |
| 11 | Engineer | Has C:\Apps AND V-Drive access |
| 12 | Standard | Default for other domain PCs |
**Note:** Priority matters - a PC with both Dashboard and CMM software will be classified as "Dashboard".
---
## Supporting Files
### Required Directory Structure
```
S:\dt\shopfloor\scripts\complete-asset\
├── Update-PC-CompleteAsset.ps1 # Main script
└── Get-ShopfloorConfig.ps1 # Helper functions (REQUIRED)
```
**Important:** Both files must be in the same directory. The main script dot-sources the helper:
```powershell
. "$PSScriptRoot\Get-ShopfloorConfig.ps1"
```
### Get-ShopfloorConfig.ps1
Helper script providing these functions:
| Function | Purpose |
|----------|---------|
| `Get-NetworkInterfaceConfig` | Network adapters with IsPrimary/IsMachineNetwork |
| `Get-SerialPortConfig` | DNC serial port settings |
| `Get-GERegistryInfo` | GE Aircraft Engines registry (DualPath, paths) |
| `Get-DNCConfig` | DNC general configuration |
| `Get-ShopfloorConfigurations` | Combines all above into one call |
| `Get-InstalledApplications` | Detects UDC/CLM processes |
### applications.csv
Defines tracked applications for version tracking:
```csv
app_id,app_name,search_patterns
2,UDC,"Universal Data Collector"
4,CLM,"Cell Level Manager|ppdcs"
77,HeatTreat,"HeatTreat"
82,GE Aerospace Dashboard,"GE Aerospace Dashboard"
83,GE Aerospace Lobby Display,"GE Aerospace Lobby Display"
```
**Location:** `S:\dt\shopfloor\scripts\applications.csv`
---
## Comparison with Remote Script
| Feature | Local Script | Remote Script |
|---------|-------------|---------------|
| Execution | On target PC | From admin workstation |
| WinRM Required | No | Yes |
| V-Drive Detection | Yes | No |
| C:\Apps Detection | Yes | Limited |
| Batch Operations | No (one PC) | Yes (many PCs) |
| User Context | Local user | WinRM context |
| Admin Rights | Needed locally | Needed remotely |

View File

@@ -0,0 +1,864 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Update-ShopfloorPCs-Remote.ps1</title>
<style>
* {
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
line-height: 1.6;
max-width: 900px;
margin: 0 auto;
padding: 20px 40px;
background-color: #ffffff;
color: #333;
}
h1 {
color: #1a5276;
border-bottom: 3px solid #1a5276;
padding-bottom: 10px;
margin-top: 0;
}
h2 {
color: #2874a6;
border-bottom: 2px solid #d5dbdb;
padding-bottom: 8px;
margin-top: 40px;
}
h3 {
color: #2e86ab;
margin-top: 30px;
}
h4 {
color: #5d6d7e;
margin-top: 25px;
}
a {
color: #2980b9;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
code {
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
background-color: #f4f4f4;
padding: 2px 6px;
border-radius: 3px;
font-size: 0.9em;
border: 1px solid #e1e1e1;
}
pre {
background-color: #2d2d2d;
color: #f8f8f2;
padding: 15px 20px;
border-radius: 6px;
overflow-x: auto;
font-family: 'Cascadia Mono', 'JetBrains Mono', 'Fira Code', 'Source Code Pro', 'DejaVu Sans Mono', 'Consolas', 'Monaco', 'Courier New', monospace;
font-size: 14px;
line-height: 1.4;
border: 1px solid #444;
margin: 15px 0;
-webkit-font-feature-settings: "liga" 0;
font-feature-settings: "liga" 0;
letter-spacing: 0;
}
pre code {
background-color: transparent;
padding: 0;
border: none;
color: inherit;
font-size: inherit;
}
table {
border-collapse: collapse;
width: 100%;
margin: 15px 0;
font-size: 14px;
}
th, td {
border: 1px solid #ddd;
padding: 10px 12px;
text-align: left;
}
th {
background-color: #34495e;
color: white;
font-weight: 600;
}
tr:nth-child(even) {
background-color: #f9f9f9;
}
tr:hover {
background-color: #f1f1f1;
}
ul, ol {
padding-left: 25px;
}
li {
margin-bottom: 5px;
}
blockquote {
border-left: 4px solid #3498db;
margin: 15px 0;
padding: 10px 20px;
background-color: #f8f9fa;
color: #555;
}
hr {
border: none;
border-top: 2px solid #eee;
margin: 30px 0;
}
.toc {
background-color: #f8f9fa;
border: 1px solid #e9ecef;
border-radius: 6px;
padding: 20px;
margin-bottom: 30px;
}
.toc h2 {
margin-top: 0;
border-bottom: none;
font-size: 1.2em;
}
.toc ul {
list-style-type: none;
padding-left: 0;
}
.toc li {
margin-bottom: 8px;
}
.toc a {
color: #2c3e50;
}
.note {
background-color: #fff3cd;
border-left: 4px solid #ffc107;
padding: 10px 15px;
margin: 15px 0;
}
.warning {
background-color: #f8d7da;
border-left: 4px solid #dc3545;
padding: 10px 15px;
margin: 15px 0;
}
@media print {
body {
max-width: 100%;
padding: 20px;
}
pre {
white-space: pre-wrap;
word-wrap: break-word;
}
h2 {
page-break-before: auto;
}
pre, table {
page-break-inside: avoid;
}
}
</style>
</head>
<body>
<h1 id="update-shopfloorpcs-remoteps1">Update-ShopfloorPCs-Remote.ps1</h1>
<p>Remote data collection script that gathers PC information from shopfloor PCs via WinRM and updates the ShopDB database.</p>
<h2 id="table-of-contents">Table of Contents</h2>
<ul>
<li><a href="#overview">Overview</a></li>
<li><a href="#api-integration">API Integration</a></li>
<li><a href="#prerequisites">Prerequisites</a></li>
<li><a href="#quick-start">Quick Start</a></li>
<li><a href="#parameters-reference">Parameters Reference</a></li>
<li><a href="#how-to-guides">How-To Guides</a></li>
<li><a href="#data-collected">Data Collected</a></li>
<li><a href="#pc-type-detection">PC Type Detection</a></li>
<li><a href="#troubleshooting">Troubleshooting</a></li>
<li><a href="#advanced-usage">Advanced Usage</a></li>
<li><a href="#script-files">Script Files</a></li>
</ul>
<hr>
<h2 id="overview">Overview</h2>
<p>This script remotely connects to shopfloor PCs using Windows Remote Management (WinRM) to collect comprehensive system information including hardware details, network configuration, DNC settings, and installed applications. The collected data is then sent to the ShopDB API for asset tracking.</p>
<p><strong>Location:</strong> <code>S:\dt\shopfloor\scripts\remote-execution\Update-ShopfloorPCs-Remote.ps1</code></p>
<p><strong>Use Cases:</strong></p>
<ul>
<li>Bulk asset inventory updates</li>
<li>Automated PC discovery and classification</li>
<li>Scheduled data collection from all shopfloor PCs</li>
<li>Targeted updates for specific machines or groups</li>
</ul>
<hr>
<h2 id="api-integration">API Integration</h2>
<p>This script interacts with the ShopDB API (<code>api.asp</code>) for both retrieving PC lists and storing collected data.</p>
<h3 id="retrieving-pc-lists">Retrieving PC Lists</h3>
<p>When using <code>-All</code>, the script queries the API to get the list of shopfloor PCs:</p>
<pre><code>GET /api.asp?action=getShopfloorPCs</code></pre>
<p>This returns all active PCs with 10.134.<em>.</em> IP addresses. Optional filters:</p>
<ul>
<li><code>pctypeid</code> - Filter by PC type (1=Shopfloor, 2=CMM, etc.)</li>
<li><code>businessunitid</code> - Filter by business unit</li>
</ul>
<h3 id="retrieving-high-uptime-pcs">Retrieving High Uptime PCs</h3>
<p>When using <code>-Reboot</code>, the script queries:</p>
<pre><code>GET /api.asp?action=getHighUptimePCs&amp;minUptime=30</code></pre>
<p>This returns PCs that haven't been rebooted in the specified number of days.</p>
<h3 id="storing-collected-data">Storing Collected Data</h3>
<p>After collecting data from each PC, the script POSTs to:</p>
<pre><code>POST /api.asp?action=updateCompleteAsset</code></pre>
<p>With parameters including hostname, serial number, network interfaces, DNC config, and installed applications.</p>
<p><strong>See:</strong> <a href="ShopDB-API.html">ShopDB API Reference</a> for complete API documentation.</p>
<hr>
<h2 id="prerequisites">Prerequisites</h2>
<h3 id="on-your-workstation-where-you-run-the-script">On Your Workstation (Where You Run the Script)</h3>
<ol>
<li><strong>PowerShell 5.1 or higher</strong></li>
</ol>
<pre><code class="language-powershell"> $PSVersionTable.PSVersion</code></pre>
<ol>
<li><strong>Network access to target PCs</strong> on port 5985 (HTTP) or 5986 (HTTPS)</li>
</ol>
<ol>
<li><strong>Domain admin or local admin credentials</strong> for target PCs</li>
</ol>
<h3 id="on-target-pcs">On Target PCs</h3>
<ol>
<li><strong>WinRM must be enabled</strong></li>
</ol>
<pre><code class="language-powershell"> # Check if WinRM is running
Get-Service WinRM
# Enable WinRM (run as admin on target PC)
Enable-PSRemoting -Force</code></pre>
<ol>
<li><strong>Firewall rules</strong> allowing WinRM traffic (TCP 5985/5986)</li>
</ol>
<h3 id="winrm-trusted-hosts-setup">WinRM Trusted Hosts Setup</h3>
<p>If your workstation is not domain-joined or targets are in a different domain:</p>
<pre><code class="language-powershell"># Option 1: Use the script&#x27;s built-in setup
.\Update-ShopfloorPCs-Remote.ps1 -SetupTrustedHosts
# Option 2: Manual setup (run as admin)
Set-Item WSMan:\localhost\Client\TrustedHosts -Value &quot;192.168.*&quot; -Force
Set-Item WSMan:\localhost\Client\TrustedHosts -Value &quot;10.134.*&quot; -Concatenate -Force</code></pre>
<hr>
<h2 id="quick-start">Quick Start</h2>
<h3 id="step-1-open-powershell-as-administrator">Step 1: Open PowerShell as Administrator</h3>
<pre><code class="language-powershell"># Navigate to script directory
cd C:\Path\To\powershell\remote-execution</code></pre>
<h3 id="step-2-get-credentials">Step 2: Get Credentials</h3>
<pre><code class="language-powershell"># Store credentials for the session
$cred = Get-Credential -Message &quot;Enter domain admin credentials&quot;</code></pre>
<h3 id="step-3-run-your-first-collection">Step 3: Run Your First Collection</h3>
<pre><code class="language-powershell"># Test with a single PC
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName &quot;SHOPFLOOR-PC01&quot; -Credential $cred</code></pre>
<h3 id="step-4-verify-results">Step 4: Verify Results</h3>
<p>Check the ShopDB database or web interface to confirm the PC data was updated.</p>
<hr>
<h2 id="parameters-reference">Parameters Reference</h2>
<h3 id="targeting-parameters">Targeting Parameters</h3>
<table>
<thead><tr>
<th>Parameter</th>
<th>Type</th>
<th>Description</th>
</tr></thead>
<tbody>
<tr>
<td><code>-ComputerName</code></td>
<td>string[]</td>
<td>One or more computer names to target</td>
</tr>
<tr>
<td><code>-All</code></td>
<td>switch</td>
<td>Query ShopDB for all shopfloor PCs</td>
</tr>
</tbody></table>
<h3 id="authentication-parameters">Authentication Parameters</h3>
<table>
<thead><tr>
<th>Parameter</th>
<th>Type</th>
<th>Default</th>
<th>Description</th>
</tr></thead>
<tbody>
<tr>
<td><code>-Credential</code></td>
<td>PSCredential</td>
<td>Prompt</td>
<td>Admin credentials for remote access</td>
</tr>
<tr>
<td><code>-UseSSL</code></td>
<td>switch</td>
<td>False</td>
<td>Use HTTPS (port 5986) instead of HTTP</td>
</tr>
</tbody></table>
<h3 id="api-parameters">API Parameters</h3>
<table>
<thead><tr>
<th>Parameter</th>
<th>Type</th>
<th>Default</th>
<th>Description</th>
</tr></thead>
<tbody>
<tr>
<td><code>-ApiUrl</code></td>
<td>string</td>
<td>Production URL</td>
<td>ShopDB API endpoint</td>
</tr>
</tbody></table>
<h3 id="network-parameters">Network Parameters</h3>
<table>
<thead><tr>
<th>Parameter</th>
<th>Type</th>
<th>Default</th>
<th>Description</th>
</tr></thead>
<tbody>
<tr>
<td><code>-DnsSuffix</code></td>
<td>string</td>
<td>logon.ds.ge.com</td>
<td>DNS suffix for FQDN resolution</td>
</tr>
<tr>
<td><code>-SkipDnsLookup</code></td>
<td>switch</td>
<td>False</td>
<td>Use hostnames as-is without DNS</td>
</tr>
<tr>
<td><code>-ThrottleLimit</code></td>
<td>int</td>
<td>25</td>
<td>Max concurrent remote sessions</td>
</tr>
</tbody></table>
<h3 id="reboot-parameters">Reboot Parameters</h3>
<table>
<thead><tr>
<th>Parameter</th>
<th>Type</th>
<th>Description</th>
</tr></thead>
<tbody>
<tr>
<td><code>-Reboot</code></td>
<td>switch</td>
<td>Enable reboot mode</td>
</tr>
<tr>
<td><code>-MinUptimeDays</code></td>
<td>int</td>
<td>Minimum uptime threshold for reboot</td>
</tr>
<tr>
<td><code>-Force</code></td>
<td>switch</td>
<td>Skip confirmation prompts</td>
</tr>
<tr>
<td><code>-WhatIf</code></td>
<td>switch</td>
<td>Preview without executing</td>
</tr>
</tbody></table>
<h3 id="setup-parameters">Setup Parameters</h3>
<table>
<thead><tr>
<th>Parameter</th>
<th>Type</th>
<th>Description</th>
</tr></thead>
<tbody>
<tr>
<td><code>-SetupTrustedHosts</code></td>
<td>switch</td>
<td>Configure WinRM trusted hosts</td>
</tr>
</tbody></table>
<hr>
<h2 id="how-to-guides">How-To Guides</h2>
<h3 id="how-to-update-a-single-pc">How to Update a Single PC</h3>
<p><strong>Scenario:</strong> You need to update asset data for one specific PC.</p>
<pre><code class="language-powershell"># Basic usage
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName &quot;G1ZTNCX3ESF&quot;
# With credentials (avoids prompt)
$cred = Get-Credential
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName &quot;G1ZTNCX3ESF&quot; -Credential $cred
# Using IP address instead of hostname
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName &quot;10.134.50.101&quot; -SkipDnsLookup</code></pre>
<p><strong>Expected Output:</strong></p>
<pre><code>Connecting to G1ZTNCX3ESF...
[OK] Connected successfully
Collecting system information...
Hostname: G1ZTNCX3ESF
Serial: ABC1234
PC Type: Shopfloor
Sending data to API...
[OK] Data stored successfully (PCID: 1234)</code></pre>
<hr>
<h3 id="how-to-update-multiple-pcs">How to Update Multiple PCs</h3>
<p><strong>Scenario:</strong> You have a list of PCs that need updating.</p>
<pre><code class="language-powershell"># Array of computer names
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName &quot;PC01&quot;,&quot;PC02&quot;,&quot;PC03&quot;,&quot;PC04&quot;
# From a variable
$pcs = @(&quot;SHOPFLOOR-01&quot;, &quot;SHOPFLOOR-02&quot;, &quot;SHOPFLOOR-03&quot;)
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName $pcs -Credential $cred
# From a text file (one hostname per line)
$pcs = Get-Content &quot;C:\Lists\shopfloor-pcs.txt&quot;
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName $pcs -Credential $cred</code></pre>
<p><strong>Adjusting Concurrency:</strong></p>
<pre><code class="language-powershell"># Slower network - reduce concurrent connections
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName $pcs -ThrottleLimit 5
# Fast network - increase concurrent connections
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName $pcs -ThrottleLimit 50</code></pre>
<hr>
<h3 id="how-to-update-all-shopfloor-pcs">How to Update All Shopfloor PCs</h3>
<p><strong>Scenario:</strong> Scheduled full inventory update of all shopfloor PCs.</p>
<pre><code class="language-powershell"># Update all PCs from ShopDB database
.\Update-ShopfloorPCs-Remote.ps1 -All -Credential $cred
# With lower throttle for off-hours
.\Update-ShopfloorPCs-Remote.ps1 -All -Credential $cred -ThrottleLimit 10</code></pre>
<p><strong>Scheduling with Task Scheduler:</strong></p>
<ol>
<li>Create a batch file <code>run-collection.bat</code>:</li>
</ol>
<pre><code class="language-batch"> @echo off
powershell.exe -ExecutionPolicy Bypass -File &quot;C:\Scripts\Update-ShopfloorPCs-Remote.ps1&quot; -All</code></pre>
<ol>
<li>Create scheduled task:</li>
</ol>
<ul>
<li>Trigger: Daily at 2:00 AM</li>
<li>Action: Run <code>run-collection.bat</code></li>
<li>Run as: Service account with admin rights</li>
</ul>
<hr>
<h3 id="how-to-reboot-pcs-with-high-uptime">How to Reboot PCs with High Uptime</h3>
<p><strong>Scenario:</strong> Reboot PCs that haven't been restarted in 30+ days.</p>
<pre><code class="language-powershell"># Step 1: Preview which PCs would be rebooted
.\Update-ShopfloorPCs-Remote.ps1 -Reboot -MinUptimeDays 30 -WhatIf
# Output shows:
# Would reboot: SHOPFLOOR-01 (Uptime: 45 days)
# Would reboot: SHOPFLOOR-02 (Uptime: 62 days)
# Would skip: SHOPFLOOR-03 (Uptime: 12 days)
# Step 2: Execute with confirmation
.\Update-ShopfloorPCs-Remote.ps1 -Reboot -MinUptimeDays 30 -Credential $cred
# Prompts: &quot;Reboot 2 PCs? [Y/N]&quot;
# Step 3: Or execute without confirmation
.\Update-ShopfloorPCs-Remote.ps1 -Reboot -MinUptimeDays 30 -Force -Credential $cred</code></pre>
<p><strong>Best Practices for Reboots:</strong></p>
<ul>
<li>Always run <code>-WhatIf</code> first</li>
<li>Schedule during maintenance windows</li>
<li>Start with higher threshold (60 days) then reduce</li>
<li>Monitor for production impact</li>
</ul>
<hr>
<h3 id="how-to-set-up-winrm-trusted-hosts">How to Set Up WinRM Trusted Hosts</h3>
<p><strong>Scenario:</strong> Your workstation can't connect to shopfloor PCs.</p>
<pre><code class="language-powershell"># Use built-in setup (configures common shopfloor subnets)
.\Update-ShopfloorPCs-Remote.ps1 -SetupTrustedHosts
# Verify configuration
Get-Item WSMan:\localhost\Client\TrustedHosts
# Manual addition of specific subnet
Set-Item WSMan:\localhost\Client\TrustedHosts -Value &quot;10.134.*&quot; -Force</code></pre>
<hr>
<h3 id="how-to-use-different-api-endpoints">How to Use Different API Endpoints</h3>
<p><strong>Scenario:</strong> Testing against development or staging environments.</p>
<pre><code class="language-powershell"># Development environment
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName &quot;TEST-PC&quot; -ApiUrl &quot;http://192.168.122.151:8080/api.asp&quot;
# Staging environment
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName &quot;TEST-PC&quot; -ApiUrl &quot;https://staging-server/shopdb/api.asp&quot;</code></pre>
<hr>
<h3 id="how-to-handle-dns-resolution-issues">How to Handle DNS Resolution Issues</h3>
<p><strong>Scenario:</strong> PC hostnames aren't resolving correctly.</p>
<pre><code class="language-powershell"># Skip DNS and use hostnames as-is
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName &quot;SHOPFLOOR-01&quot; -SkipDnsLookup
# Use different DNS suffix
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName &quot;SHOPFLOOR-01&quot; -DnsSuffix &quot;shopfloor.local&quot;
# Use IP addresses directly
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName &quot;10.134.50.101&quot; -SkipDnsLookup</code></pre>
<hr>
<h3 id="how-to-use-secure-connections-ssl">How to Use Secure Connections (SSL)</h3>
<p><strong>Scenario:</strong> Security requirements mandate encrypted WinRM connections.</p>
<pre><code class="language-powershell"># Enable SSL for WinRM (uses port 5986)
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName &quot;SECURE-PC&quot; -UseSSL -Credential $cred</code></pre>
<p><strong>Prerequisites for SSL:</strong></p>
<ul>
<li>Valid certificate on target PC</li>
<li>WinRM HTTPS listener configured</li>
<li>Port 5986 open in firewall</li>
</ul>
<hr>
<h2 id="data-collected">Data Collected</h2>
<h3 id="basic-system-information">Basic System Information</h3>
<table>
<thead><tr>
<th>Field</th>
<th>Example</th>
<th>Description</th>
</tr></thead>
<tbody>
<tr>
<td>Hostname</td>
<td><code>G1ZTNCX3ESF</code></td>
<td>Computer name</td>
</tr>
<tr>
<td>Serial Number</td>
<td><code>ABC1234567</code></td>
<td>BIOS serial</td>
</tr>
<tr>
<td>Service Tag</td>
<td><code>ABC1234567</code></td>
<td>Dell service tag</td>
</tr>
<tr>
<td>Manufacturer</td>
<td><code>Dell Inc.</code></td>
<td>System manufacturer</td>
</tr>
<tr>
<td>Model</td>
<td><code>OptiPlex 7080</code></td>
<td>System model</td>
</tr>
<tr>
<td>OS Version</td>
<td><code>Microsoft Windows 10 Enterprise</code></td>
<td>Windows edition</td>
</tr>
<tr>
<td>Last Boot Time</td>
<td><code>2025-01-15 08:30:00</code></td>
<td>Last restart</td>
</tr>
<tr>
<td>Total Physical Memory</td>
<td><code>16.0</code></td>
<td>RAM in GB</td>
</tr>
<tr>
<td>Domain Role</td>
<td><code>1</code></td>
<td>0=Standalone, 1=Member Workstation</td>
</tr>
<tr>
<td>Current Time Zone</td>
<td><code>Eastern Standard Time</code></td>
<td>System timezone</td>
</tr>
<tr>
<td>Logged In User</td>
<td><code>DOMAIN\jsmith</code></td>
<td>Current user</td>
</tr>
</tbody></table>
<h3 id="dnc-configuration">DNC Configuration</h3>
<table>
<thead><tr>
<th>Field</th>
<th>Example</th>
<th>Description</th>
</tr></thead>
<tbody>
<tr>
<td>Site</td>
<td><code>WJF</code></td>
<td>GE site code</td>
</tr>
<tr>
<td>CNC</td>
<td><code>FANUC</code></td>
<td>CNC controller type</td>
</tr>
<tr>
<td>NcIF</td>
<td><code>FOCAS2</code></td>
<td>NC interface protocol</td>
</tr>
<tr>
<td>Machine No</td>
<td><code>M0612</code></td>
<td>GE machine number</td>
</tr>
<tr>
<td>FTP Primary</td>
<td><code>10.134.50.10</code></td>
<td>Primary FTP server</td>
</tr>
<tr>
<td>FTP Secondary</td>
<td><code>10.134.50.11</code></td>
<td>Backup FTP server</td>
</tr>
</tbody></table>
<h3 id="network-interfaces">Network Interfaces</h3>
<table>
<thead><tr>
<th>Field</th>
<th>Example</th>
<th>Description</th>
</tr></thead>
<tbody>
<tr>
<td>Interface Name</td>
<td><code>Ethernet0</code></td>
<td>Adapter name</td>
</tr>
<tr>
<td>IP Address</td>
<td><code>10.134.50.101</code></td>
<td>IPv4 address</td>
</tr>
<tr>
<td>Subnet Mask</td>
<td><code>24</code></td>
<td>CIDR prefix</td>
</tr>
<tr>
<td>Default Gateway</td>
<td><code>10.134.50.1</code></td>
<td>Gateway</td>
</tr>
<tr>
<td>MAC Address</td>
<td><code>00-11-22-33-44-55</code></td>
<td>Physical address</td>
</tr>
<tr>
<td>Is Primary</td>
<td><code>1</code></td>
<td>10.134.<em>.</em> network</td>
</tr>
<tr>
<td>Is Machine Network</td>
<td><code>0</code></td>
<td>192.168.<em>.</em> or 100.0.0.* network (CMM)</td>
</tr>
</tbody></table>
<h3 id="additional-data">Additional Data</h3>
<table>
<thead><tr>
<th>Field</th>
<th>Example</th>
<th>Description</th>
</tr></thead>
<tbody>
<tr>
<td>Serial Ports</td>
<td><code>COM1, COM2</code></td>
<td>Available COM ports</td>
</tr>
<tr>
<td>Has VNC</td>
<td><code>1</code></td>
<td>VNC Server installed</td>
</tr>
<tr>
<td>Default Printer</td>
<td><code>10.80.92.53</code></td>
<td>Network printer port</td>
</tr>
<tr>
<td>All Installed Apps</td>
<td><code>Microsoft Office...</code></td>
<td>Complete app list</td>
</tr>
</tbody></table>
<hr>
<h2 id="pc-type-detection">PC Type Detection</h2>
<p>The script automatically classifies PCs based on installed software:</p>
<table>
<thead><tr>
<th>Priority</th>
<th>Type</th>
<th>Detection Criteria</th>
</tr></thead>
<tbody>
<tr>
<td>1</td>
<td>Dashboard</td>
<td><code>GE Aerospace Dashboard</code> installed</td>
</tr>
<tr>
<td>2</td>
<td>Lobby Display</td>
<td><code>GE Aerospace Lobby Display</code> installed</td>
</tr>
<tr>
<td>3</td>
<td>CMM</td>
<td>PC-DMIS, goCMM, or DODA software</td>
</tr>
<tr>
<td>4</td>
<td>Wax Trace</td>
<td>FormTracePak or FormStatusMonitor</td>
</tr>
<tr>
<td>5</td>
<td>Keyence</td>
<td>VR-3000, VR-5000, or VR-6000</td>
</tr>
<tr>
<td>6</td>
<td>EAS1000</td>
<td>GageCal or NI Software</td>
</tr>
<tr>
<td>7</td>
<td>Genspect</td>
<td>Genspect measuring software</td>
</tr>
<tr>
<td>8</td>
<td>Heat Treat</td>
<td>HeatTreat application</td>
</tr>
<tr>
<td>9</td>
<td>Inspection</td>
<td>Machine #: 0612, 0613, 0615, 8003</td>
</tr>
<tr>
<td>10</td>
<td>Shopfloor</td>
<td>Default for domain shop PCs</td>
</tr>
</tbody></table>
<hr>
<h2 id="troubleshooting">Troubleshooting</h2>
<h3 id="error-winrm-cannot-process-the-request">Error: "WinRM cannot process the request"</h3>
<p><strong>Cause:</strong> WinRM not enabled on target PC.</p>
<p><strong>Solution:</strong></p>
<pre><code class="language-powershell"># On target PC (as admin)
Enable-PSRemoting -Force
Set-Service WinRM -StartupType Automatic
Start-Service WinRM</code></pre>
<hr>
<h3 id="error-access-is-denied">Error: "Access is denied"</h3>
<p><strong>Cause:</strong> Insufficient credentials or UAC blocking remote admin.</p>
<p><strong>Solutions:</strong></p>
<pre><code class="language-powershell"># 1. Use explicit domain credentials
$cred = Get-Credential -UserName &quot;DOMAIN\AdminUser&quot; -Message &quot;Enter password&quot;
# 2. On target PC, enable remote UAC (as admin)
Set-ItemProperty -Path &quot;HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System&quot; -Name &quot;LocalAccountTokenFilterPolicy&quot; -Value 1 -Type DWord</code></pre>
<hr>
<h3 id="error-the-winrm-client-cannot-process-the-request-not-in-trustedhosts">Error: "The WinRM client cannot process the request... not in TrustedHosts"</h3>
<p><strong>Cause:</strong> Target not in trusted hosts list.</p>
<p><strong>Solution:</strong></p>
<pre><code class="language-powershell">.\Update-ShopfloorPCs-Remote.ps1 -SetupTrustedHosts
# Or manually:
Set-Item WSMan:\localhost\Client\TrustedHosts -Value &quot;10.134.*&quot; -Force</code></pre>
<hr>
<h3 id="error-the-underlying-connection-was-closed">Error: "The underlying connection was closed"</h3>
<p><strong>Cause:</strong> TLS/SSL configuration mismatch.</p>
<p><strong>Solution:</strong> The script automatically sets TLS 1.2/1.3. If issues persist:</p>
<pre><code class="language-powershell"># Force TLS 1.2 before running
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12</code></pre>
<hr>
<h3 id="error-cannot-find-computer-or-dns-failures">Error: "Cannot find computer" or DNS failures</h3>
<p><strong>Cause:</strong> Hostname not resolving.</p>
<p><strong>Solutions:</strong></p>
<pre><code class="language-powershell"># 1. Skip DNS resolution
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName &quot;PC01&quot; -SkipDnsLookup
# 2. Use IP address
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName &quot;10.134.50.101&quot; -SkipDnsLookup
# 3. Use different DNS suffix
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName &quot;PC01&quot; -DnsSuffix &quot;yourdomain.local&quot;</code></pre>
<hr>
<h3 id="slow-performance-with-many-pcs">Slow Performance with Many PCs</h3>
<p><strong>Cause:</strong> Network bandwidth or target PC load.</p>
<p><strong>Solutions:</strong></p>
<pre><code class="language-powershell"># Reduce concurrent connections
.\Update-ShopfloorPCs-Remote.ps1 -All -ThrottleLimit 5
# Run in batches
$allPCs = Get-Content &quot;all-pcs.txt&quot;
$batch1 = $allPCs[0..49]
$batch2 = $allPCs[50..99]
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName $batch1 -Credential $cred
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName $batch2 -Credential $cred</code></pre>
<hr>
<h2 id="advanced-usage">Advanced Usage</h2>
<h3 id="combining-with-other-scripts">Combining with Other Scripts</h3>
<pre><code class="language-powershell"># Collect data first, then run maintenance
.\Update-ShopfloorPCs-Remote.ps1 -All -Credential $cred
.\Invoke-RemoteMaintenance.ps1 -All -Task SyncTime -Credential $cred</code></pre>
<h3 id="exporting-results-for-analysis">Exporting Results for Analysis</h3>
<pre><code class="language-powershell"># Capture output to file
.\Update-ShopfloorPCs-Remote.ps1 -All -Credential $cred | Tee-Object -FilePath &quot;collection-log.txt&quot;</code></pre>
<hr>
<h2 id="script-files">Script Files</h2>
<h3 id="current-scripts-active">Current Scripts (Active)</h3>
<pre><code>S:\dt\shopfloor\scripts\
├── remote-execution\
│ ├── Update-ShopfloorPCs-Remote.ps1 # Remote data collection (this script)
│ └── Invoke-RemoteMaintenance.ps1 # Remote maintenance tasks
└── complete-asset\
├── Update-PC-CompleteAsset.ps1 # Local data collection
└── Get-ShopfloorConfig.ps1 # Helper functions (required by above)</code></pre>
<h3 id="deprecated-scripts-can-be-removed">Deprecated Scripts (Can Be Removed)</h3>
<p>The following scripts in <code>remote-execution\</code> are legacy and have been replaced:</p>
<table>
<thead><tr>
<th>Deprecated Script</th>
<th>Replaced By</th>
</tr></thead>
<tbody>
<tr>
<td><code>Invoke-RemoteAssetCollection.ps1</code></td>
<td><code>Update-ShopfloorPCs-Remote.ps1</code></td>
</tr>
<tr>
<td><code>Invoke-RemoteAssetCollection-HTTPS.ps1</code></td>
<td><code>Update-ShopfloorPCs-Remote.ps1 -UseSSL</code></td>
</tr>
<tr>
<td><code>Install-KioskApp.ps1</code></td>
<td><code>Invoke-RemoteMaintenance.ps1 -Task InstallDashboard</code></td>
</tr>
<tr>
<td><code>Test-UserRegistryDetection.ps1</code></td>
<td>Functionality integrated into main scripts</td>
</tr>
</tbody></table>
<p>These deprecated scripts can be archived or deleted.</p>
</body>
</html>

View File

@@ -0,0 +1,582 @@
# Update-ShopfloorPCs-Remote.ps1
Remote data collection script that gathers PC information from shopfloor PCs via WinRM and updates the ShopDB database.
## Table of Contents
- [Overview](#overview)
- [API Integration](#api-integration)
- [Prerequisites](#prerequisites)
- [Quick Start](#quick-start)
- [Parameters Reference](#parameters-reference)
- [How-To Guides](#how-to-guides)
- [Data Collected](#data-collected)
- [PC Type Detection](#pc-type-detection)
- [Troubleshooting](#troubleshooting)
- [Advanced Usage](#advanced-usage)
- [Script Files](#script-files)
---
## Overview
This script remotely connects to shopfloor PCs using Windows Remote Management (WinRM) to collect comprehensive system information including hardware details, network configuration, DNC settings, and installed applications. The collected data is then sent to the ShopDB API for asset tracking.
**Location:** `S:\dt\shopfloor\scripts\remote-execution\Update-ShopfloorPCs-Remote.ps1`
**Use Cases:**
- Bulk asset inventory updates
- Automated PC discovery and classification
- Scheduled data collection from all shopfloor PCs
- Targeted updates for specific machines or groups
---
## API Integration
This script interacts with the ShopDB API (`api.asp`) for both retrieving PC lists and storing collected data.
### Retrieving PC Lists
When using `-All`, the script queries the API to get the list of shopfloor PCs:
```
GET /api.asp?action=getShopfloorPCs
```
This returns all active PCs with 10.134.*.* IP addresses. Optional filters:
- `pctypeid` - Filter by PC type (1=Shopfloor, 2=CMM, etc.)
- `businessunitid` - Filter by business unit
### Retrieving High Uptime PCs
When using `-Reboot`, the script queries:
```
GET /api.asp?action=getHighUptimePCs&minUptime=30
```
This returns PCs that haven't been rebooted in the specified number of days.
### Storing Collected Data
After collecting data from each PC, the script POSTs to:
```
POST /api.asp?action=updateCompleteAsset
```
With parameters including hostname, serial number, network interfaces, DNC config, and installed applications.
**See:** [ShopDB API Reference](ShopDB-API.html) for complete API documentation.
---
## Prerequisites
### On Your Workstation (Where You Run the Script)
1. **PowerShell 5.1 or higher**
```powershell
$PSVersionTable.PSVersion
```
2. **Network access to target PCs** on port 5985 (HTTP) or 5986 (HTTPS)
3. **Domain admin or local admin credentials** for target PCs
### On Target PCs
1. **WinRM must be enabled**
```powershell
# Check if WinRM is running
Get-Service WinRM
# Enable WinRM (run as admin on target PC)
Enable-PSRemoting -Force
```
2. **Firewall rules** allowing WinRM traffic (TCP 5985/5986)
### WinRM Trusted Hosts Setup
If your workstation is not domain-joined or targets are in a different domain:
```powershell
# Option 1: Use the script's built-in setup
.\Update-ShopfloorPCs-Remote.ps1 -SetupTrustedHosts
# Option 2: Manual setup (run as admin)
Set-Item WSMan:\localhost\Client\TrustedHosts -Value "192.168.*" -Force
Set-Item WSMan:\localhost\Client\TrustedHosts -Value "10.134.*" -Concatenate -Force
```
---
## Quick Start
### Step 1: Open PowerShell as Administrator
```powershell
# Navigate to script directory
cd C:\Path\To\powershell\remote-execution
```
### Step 2: Get Credentials
```powershell
# Store credentials for the session
$cred = Get-Credential -Message "Enter domain admin credentials"
```
### Step 3: Run Your First Collection
```powershell
# Test with a single PC
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "SHOPFLOOR-PC01" -Credential $cred
```
### Step 4: Verify Results
Check the ShopDB database or web interface to confirm the PC data was updated.
---
## Parameters Reference
### Targeting Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `-ComputerName` | string[] | One or more computer names to target |
| `-All` | switch | Query ShopDB for all shopfloor PCs |
### Authentication Parameters
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `-Credential` | PSCredential | Prompt | Admin credentials for remote access |
| `-UseSSL` | switch | False | Use HTTPS (port 5986) instead of HTTP |
### API Parameters
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `-ApiUrl` | string | Production URL | ShopDB API endpoint |
### Network Parameters
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `-DnsSuffix` | string | logon.ds.ge.com | DNS suffix for FQDN resolution |
| `-SkipDnsLookup` | switch | False | Use hostnames as-is without DNS |
| `-ThrottleLimit` | int | 25 | Max concurrent remote sessions |
### Reboot Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `-Reboot` | switch | Enable reboot mode |
| `-MinUptimeDays` | int | Minimum uptime threshold for reboot |
| `-Force` | switch | Skip confirmation prompts |
| `-WhatIf` | switch | Preview without executing |
### Setup Parameters
| Parameter | Type | Description |
|-----------|------|-------------|
| `-SetupTrustedHosts` | switch | Configure WinRM trusted hosts |
---
## How-To Guides
### How to Update a Single PC
**Scenario:** You need to update asset data for one specific PC.
```powershell
# Basic usage
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "G1ZTNCX3ESF"
# With credentials (avoids prompt)
$cred = Get-Credential
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "G1ZTNCX3ESF" -Credential $cred
# Using IP address instead of hostname
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "10.134.50.101" -SkipDnsLookup
```
**Expected Output:**
```
Connecting to G1ZTNCX3ESF...
[OK] Connected successfully
Collecting system information...
Hostname: G1ZTNCX3ESF
Serial: ABC1234
PC Type: Shopfloor
Sending data to API...
[OK] Data stored successfully (PCID: 1234)
```
---
### How to Update Multiple PCs
**Scenario:** You have a list of PCs that need updating.
```powershell
# Array of computer names
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "PC01","PC02","PC03","PC04"
# From a variable
$pcs = @("SHOPFLOOR-01", "SHOPFLOOR-02", "SHOPFLOOR-03")
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName $pcs -Credential $cred
# From a text file (one hostname per line)
$pcs = Get-Content "C:\Lists\shopfloor-pcs.txt"
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName $pcs -Credential $cred
```
**Adjusting Concurrency:**
```powershell
# Slower network - reduce concurrent connections
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName $pcs -ThrottleLimit 5
# Fast network - increase concurrent connections
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName $pcs -ThrottleLimit 50
```
---
### How to Update All Shopfloor PCs
**Scenario:** Scheduled full inventory update of all shopfloor PCs.
```powershell
# Update all PCs from ShopDB database
.\Update-ShopfloorPCs-Remote.ps1 -All -Credential $cred
# With lower throttle for off-hours
.\Update-ShopfloorPCs-Remote.ps1 -All -Credential $cred -ThrottleLimit 10
```
**Scheduling with Task Scheduler:**
1. Create a batch file `run-collection.bat`:
```batch
@echo off
powershell.exe -ExecutionPolicy Bypass -File "C:\Scripts\Update-ShopfloorPCs-Remote.ps1" -All
```
2. Create scheduled task:
- Trigger: Daily at 2:00 AM
- Action: Run `run-collection.bat`
- Run as: Service account with admin rights
---
### How to Reboot PCs with High Uptime
**Scenario:** Reboot PCs that haven't been restarted in 30+ days.
```powershell
# Step 1: Preview which PCs would be rebooted
.\Update-ShopfloorPCs-Remote.ps1 -Reboot -MinUptimeDays 30 -WhatIf
# Output shows:
# Would reboot: SHOPFLOOR-01 (Uptime: 45 days)
# Would reboot: SHOPFLOOR-02 (Uptime: 62 days)
# Would skip: SHOPFLOOR-03 (Uptime: 12 days)
# Step 2: Execute with confirmation
.\Update-ShopfloorPCs-Remote.ps1 -Reboot -MinUptimeDays 30 -Credential $cred
# Prompts: "Reboot 2 PCs? [Y/N]"
# Step 3: Or execute without confirmation
.\Update-ShopfloorPCs-Remote.ps1 -Reboot -MinUptimeDays 30 -Force -Credential $cred
```
**Best Practices for Reboots:**
- Always run `-WhatIf` first
- Schedule during maintenance windows
- Start with higher threshold (60 days) then reduce
- Monitor for production impact
---
### How to Set Up WinRM Trusted Hosts
**Scenario:** Your workstation can't connect to shopfloor PCs.
```powershell
# Use built-in setup (configures common shopfloor subnets)
.\Update-ShopfloorPCs-Remote.ps1 -SetupTrustedHosts
# Verify configuration
Get-Item WSMan:\localhost\Client\TrustedHosts
# Manual addition of specific subnet
Set-Item WSMan:\localhost\Client\TrustedHosts -Value "10.134.*" -Force
```
---
### How to Use Different API Endpoints
**Scenario:** Testing against development or staging environments.
```powershell
# Development environment
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "TEST-PC" -ApiUrl "http://192.168.122.151:8080/api.asp"
# Staging environment
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "TEST-PC" -ApiUrl "https://staging-server/shopdb/api.asp"
```
---
### How to Handle DNS Resolution Issues
**Scenario:** PC hostnames aren't resolving correctly.
```powershell
# Skip DNS and use hostnames as-is
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "SHOPFLOOR-01" -SkipDnsLookup
# Use different DNS suffix
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "SHOPFLOOR-01" -DnsSuffix "shopfloor.local"
# Use IP addresses directly
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "10.134.50.101" -SkipDnsLookup
```
---
### How to Use Secure Connections (SSL)
**Scenario:** Security requirements mandate encrypted WinRM connections.
```powershell
# Enable SSL for WinRM (uses port 5986)
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "SECURE-PC" -UseSSL -Credential $cred
```
**Prerequisites for SSL:**
- Valid certificate on target PC
- WinRM HTTPS listener configured
- Port 5986 open in firewall
---
## Data Collected
### Basic System Information
| Field | Example | Description |
|-------|---------|-------------|
| Hostname | `G1ZTNCX3ESF` | Computer name |
| Serial Number | `ABC1234567` | BIOS serial |
| Service Tag | `ABC1234567` | Dell service tag |
| Manufacturer | `Dell Inc.` | System manufacturer |
| Model | `OptiPlex 7080` | System model |
| OS Version | `Microsoft Windows 10 Enterprise` | Windows edition |
| Last Boot Time | `2025-01-15 08:30:00` | Last restart |
| Total Physical Memory | `16.0` | RAM in GB |
| Domain Role | `1` | 0=Standalone, 1=Member Workstation |
| Current Time Zone | `Eastern Standard Time` | System timezone |
| Logged In User | `DOMAIN\jsmith` | Current user |
### DNC Configuration
| Field | Example | Description |
|-------|---------|-------------|
| Site | `WJF` | GE site code |
| CNC | `FANUC` | CNC controller type |
| NcIF | `FOCAS2` | NC interface protocol |
| Machine No | `M0612` | GE machine number |
| FTP Primary | `10.134.50.10` | Primary FTP server |
| FTP Secondary | `10.134.50.11` | Backup FTP server |
### Network Interfaces
| Field | Example | Description |
|-------|---------|-------------|
| Interface Name | `Ethernet0` | Adapter name |
| IP Address | `10.134.50.101` | IPv4 address |
| Subnet Mask | `24` | CIDR prefix |
| Default Gateway | `10.134.50.1` | Gateway |
| MAC Address | `00-11-22-33-44-55` | Physical address |
| Is Primary | `1` | 10.134.*.* network |
| Is Machine Network | `0` | 192.168.*.* or 100.0.0.* network (CMM) |
### Additional Data
| Field | Example | Description |
|-------|---------|-------------|
| Serial Ports | `COM1, COM2` | Available COM ports |
| Has VNC | `1` | VNC Server installed |
| Default Printer | `10.80.92.53` | Network printer port |
| All Installed Apps | `Microsoft Office...` | Complete app list |
---
## PC Type Detection
The script automatically classifies PCs based on installed software:
| Priority | Type | Detection Criteria |
|----------|------|-------------------|
| 1 | Dashboard | `GE Aerospace Dashboard` installed |
| 2 | Lobby Display | `GE Aerospace Lobby Display` installed |
| 3 | CMM | PC-DMIS, goCMM, or DODA software |
| 4 | Wax Trace | FormTracePak or FormStatusMonitor |
| 5 | Keyence | VR-3000, VR-5000, or VR-6000 |
| 6 | EAS1000 | GageCal or NI Software |
| 7 | Genspect | Genspect measuring software |
| 8 | Heat Treat | HeatTreat application |
| 9 | Inspection | Machine #: 0612, 0613, 0615, 8003 |
| 10 | Shopfloor | Default for domain shop PCs |
---
## Troubleshooting
### Error: "WinRM cannot process the request"
**Cause:** WinRM not enabled on target PC.
**Solution:**
```powershell
# On target PC (as admin)
Enable-PSRemoting -Force
Set-Service WinRM -StartupType Automatic
Start-Service WinRM
```
---
### Error: "Access is denied"
**Cause:** Insufficient credentials or UAC blocking remote admin.
**Solutions:**
```powershell
# 1. Use explicit domain credentials
$cred = Get-Credential -UserName "DOMAIN\AdminUser" -Message "Enter password"
# 2. On target PC, enable remote UAC (as admin)
Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" -Name "LocalAccountTokenFilterPolicy" -Value 1 -Type DWord
```
---
### Error: "The WinRM client cannot process the request... not in TrustedHosts"
**Cause:** Target not in trusted hosts list.
**Solution:**
```powershell
.\Update-ShopfloorPCs-Remote.ps1 -SetupTrustedHosts
# Or manually:
Set-Item WSMan:\localhost\Client\TrustedHosts -Value "10.134.*" -Force
```
---
### Error: "The underlying connection was closed"
**Cause:** TLS/SSL configuration mismatch.
**Solution:** The script automatically sets TLS 1.2/1.3. If issues persist:
```powershell
# Force TLS 1.2 before running
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
```
---
### Error: "Cannot find computer" or DNS failures
**Cause:** Hostname not resolving.
**Solutions:**
```powershell
# 1. Skip DNS resolution
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "PC01" -SkipDnsLookup
# 2. Use IP address
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "10.134.50.101" -SkipDnsLookup
# 3. Use different DNS suffix
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName "PC01" -DnsSuffix "yourdomain.local"
```
---
### Slow Performance with Many PCs
**Cause:** Network bandwidth or target PC load.
**Solutions:**
```powershell
# Reduce concurrent connections
.\Update-ShopfloorPCs-Remote.ps1 -All -ThrottleLimit 5
# Run in batches
$allPCs = Get-Content "all-pcs.txt"
$batch1 = $allPCs[0..49]
$batch2 = $allPCs[50..99]
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName $batch1 -Credential $cred
.\Update-ShopfloorPCs-Remote.ps1 -ComputerName $batch2 -Credential $cred
```
---
## Advanced Usage
### Combining with Other Scripts
```powershell
# Collect data first, then run maintenance
.\Update-ShopfloorPCs-Remote.ps1 -All -Credential $cred
.\Invoke-RemoteMaintenance.ps1 -All -Task SyncTime -Credential $cred
```
### Exporting Results for Analysis
```powershell
# Capture output to file
.\Update-ShopfloorPCs-Remote.ps1 -All -Credential $cred | Tee-Object -FilePath "collection-log.txt"
```
---
## Script Files
### Current Scripts (Active)
```
S:\dt\shopfloor\scripts\
├── remote-execution\
│ ├── Update-ShopfloorPCs-Remote.ps1 # Remote data collection (this script)
│ └── Invoke-RemoteMaintenance.ps1 # Remote maintenance tasks
└── complete-asset\
├── Update-PC-CompleteAsset.ps1 # Local data collection
└── Get-ShopfloorConfig.ps1 # Helper functions (required by above)
```
### Deprecated Scripts (Can Be Removed)
The following scripts in `remote-execution\` are legacy and have been replaced:
| Deprecated Script | Replaced By |
|-------------------|-------------|
| `Invoke-RemoteAssetCollection.ps1` | `Update-ShopfloorPCs-Remote.ps1` |
| `Invoke-RemoteAssetCollection-HTTPS.ps1` | `Update-ShopfloorPCs-Remote.ps1 -UseSSL` |
| `Install-KioskApp.ps1` | `Invoke-RemoteMaintenance.ps1 -Task InstallDashboard` |
| `Test-UserRegistryDetection.ps1` | Functionality integrated into main scripts |
These deprecated scripts can be archived or deleted.

411
docs/convert_to_html.py Normal file
View File

@@ -0,0 +1,411 @@
#!/usr/bin/env python3
"""
Convert Markdown documentation to styled HTML
"""
import re
import os
import html
def convert_md_to_html(md_content, title="Documentation"):
"""Convert markdown content to styled HTML."""
# HTML template with CSS styling
html_template = '''<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{title}</title>
<style>
* {{
box-sizing: border-box;
}}
body {{
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
line-height: 1.6;
max-width: 900px;
margin: 0 auto;
padding: 20px 40px;
background-color: #ffffff;
color: #333;
}}
h1 {{
color: #1a5276;
border-bottom: 3px solid #1a5276;
padding-bottom: 10px;
margin-top: 0;
}}
h2 {{
color: #2874a6;
border-bottom: 2px solid #d5dbdb;
padding-bottom: 8px;
margin-top: 40px;
}}
h3 {{
color: #2e86ab;
margin-top: 30px;
}}
h4 {{
color: #5d6d7e;
margin-top: 25px;
}}
a {{
color: #2980b9;
text-decoration: none;
}}
a:hover {{
text-decoration: underline;
}}
code {{
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
background-color: #f4f4f4;
padding: 2px 6px;
border-radius: 3px;
font-size: 0.9em;
border: 1px solid #e1e1e1;
}}
pre {{
background-color: #2d2d2d;
color: #f8f8f2;
padding: 15px 20px;
border-radius: 6px;
overflow-x: auto;
font-family: 'Cascadia Mono', 'JetBrains Mono', 'Fira Code', 'Source Code Pro', 'DejaVu Sans Mono', 'Consolas', 'Monaco', 'Courier New', monospace;
font-size: 14px;
line-height: 1.4;
border: 1px solid #444;
margin: 15px 0;
-webkit-font-feature-settings: "liga" 0;
font-feature-settings: "liga" 0;
letter-spacing: 0;
}}
pre code {{
background-color: transparent;
padding: 0;
border: none;
color: inherit;
font-size: inherit;
}}
table {{
border-collapse: collapse;
width: 100%;
margin: 15px 0;
font-size: 14px;
}}
th, td {{
border: 1px solid #ddd;
padding: 10px 12px;
text-align: left;
}}
th {{
background-color: #34495e;
color: white;
font-weight: 600;
}}
tr:nth-child(even) {{
background-color: #f9f9f9;
}}
tr:hover {{
background-color: #f1f1f1;
}}
ul, ol {{
padding-left: 25px;
}}
li {{
margin-bottom: 5px;
}}
blockquote {{
border-left: 4px solid #3498db;
margin: 15px 0;
padding: 10px 20px;
background-color: #f8f9fa;
color: #555;
}}
hr {{
border: none;
border-top: 2px solid #eee;
margin: 30px 0;
}}
.toc {{
background-color: #f8f9fa;
border: 1px solid #e9ecef;
border-radius: 6px;
padding: 20px;
margin-bottom: 30px;
}}
.toc h2 {{
margin-top: 0;
border-bottom: none;
font-size: 1.2em;
}}
.toc ul {{
list-style-type: none;
padding-left: 0;
}}
.toc li {{
margin-bottom: 8px;
}}
.toc a {{
color: #2c3e50;
}}
.note {{
background-color: #fff3cd;
border-left: 4px solid #ffc107;
padding: 10px 15px;
margin: 15px 0;
}}
.warning {{
background-color: #f8d7da;
border-left: 4px solid #dc3545;
padding: 10px 15px;
margin: 15px 0;
}}
@media print {{
body {{
max-width: 100%;
padding: 20px;
}}
pre {{
white-space: pre-wrap;
word-wrap: break-word;
}}
h2 {{
page-break-before: auto;
}}
pre, table {{
page-break-inside: avoid;
}}
}}
</style>
</head>
<body>
{content}
</body>
</html>'''
lines = md_content.split('\n')
html_lines = []
i = 0
in_list = False
list_type = None
while i < len(lines):
line = lines[i]
# Empty line - close any open list
if not line.strip():
if in_list:
html_lines.append(f'</{list_type}>')
in_list = False
list_type = None
i += 1
continue
# Headers
if line.startswith('# '):
if in_list:
html_lines.append(f'</{list_type}>')
in_list = False
text = process_inline(line[2:].strip())
anchor = slugify(line[2:].strip())
html_lines.append(f'<h1 id="{anchor}">{text}</h1>')
i += 1
elif line.startswith('## '):
if in_list:
html_lines.append(f'</{list_type}>')
in_list = False
text = process_inline(line[3:].strip())
anchor = slugify(line[3:].strip())
html_lines.append(f'<h2 id="{anchor}">{text}</h2>')
i += 1
elif line.startswith('### '):
if in_list:
html_lines.append(f'</{list_type}>')
in_list = False
text = process_inline(line[4:].strip())
anchor = slugify(line[4:].strip())
html_lines.append(f'<h3 id="{anchor}">{text}</h3>')
i += 1
elif line.startswith('#### '):
if in_list:
html_lines.append(f'</{list_type}>')
in_list = False
text = process_inline(line[5:].strip())
anchor = slugify(line[5:].strip())
html_lines.append(f'<h4 id="{anchor}">{text}</h4>')
i += 1
# Horizontal rule
elif line.strip() == '---':
if in_list:
html_lines.append(f'</{list_type}>')
in_list = False
html_lines.append('<hr>')
i += 1
# Code blocks
elif line.strip().startswith('```'):
if in_list:
html_lines.append(f'</{list_type}>')
in_list = False
lang = line.strip()[3:]
code_lines = []
i += 1
while i < len(lines) and not lines[i].strip().startswith('```'):
code_lines.append(html.escape(lines[i]))
i += 1
code_content = '\n'.join(code_lines)
if lang:
html_lines.append(f'<pre><code class="language-{lang}">{code_content}</code></pre>')
else:
html_lines.append(f'<pre><code>{code_content}</code></pre>')
i += 1 # Skip closing ```
# Tables
elif '|' in line and i + 1 < len(lines) and '---' in lines[i + 1]:
if in_list:
html_lines.append(f'</{list_type}>')
in_list = False
html_lines.append('<table>')
# Header row
cells = [c.strip() for c in line.split('|')[1:-1]]
html_lines.append('<thead><tr>')
for cell in cells:
html_lines.append(f'<th>{process_inline(cell)}</th>')
html_lines.append('</tr></thead>')
i += 2 # Skip header and separator
html_lines.append('<tbody>')
while i < len(lines) and '|' in lines[i]:
cells = [c.strip() for c in lines[i].split('|')[1:-1]]
html_lines.append('<tr>')
for cell in cells:
html_lines.append(f'<td>{process_inline(cell)}</td>')
html_lines.append('</tr>')
i += 1
html_lines.append('</tbody></table>')
# Bullet lists
elif line.strip().startswith('- ') or line.strip().startswith('* '):
if not in_list or list_type != 'ul':
if in_list:
html_lines.append(f'</{list_type}>')
html_lines.append('<ul>')
in_list = True
list_type = 'ul'
text = process_inline(line.strip()[2:])
html_lines.append(f'<li>{text}</li>')
i += 1
# Numbered lists
elif re.match(r'^\d+\.\s', line.strip()):
if not in_list or list_type != 'ol':
if in_list:
html_lines.append(f'</{list_type}>')
html_lines.append('<ol>')
in_list = True
list_type = 'ol'
text = process_inline(re.sub(r'^\d+\.\s', '', line.strip()))
html_lines.append(f'<li>{text}</li>')
i += 1
# Blockquote
elif line.strip().startswith('>'):
if in_list:
html_lines.append(f'</{list_type}>')
in_list = False
text = process_inline(line.strip()[1:].strip())
html_lines.append(f'<blockquote>{text}</blockquote>')
i += 1
# Regular paragraph
else:
if in_list:
html_lines.append(f'</{list_type}>')
in_list = False
para_lines = [line.strip()]
i += 1
while i < len(lines) and lines[i].strip() and not lines[i].startswith('#') and not lines[i].startswith('```') and not lines[i].strip().startswith('- ') and not lines[i].strip().startswith('* ') and '|' not in lines[i] and not re.match(r'^\d+\.\s', lines[i].strip()) and lines[i].strip() != '---':
para_lines.append(lines[i].strip())
i += 1
text = process_inline(' '.join(para_lines))
html_lines.append(f'<p>{text}</p>')
# Close any remaining list
if in_list:
html_lines.append(f'</{list_type}>')
content = '\n'.join(html_lines)
return html_template.format(title=html.escape(title), content=content)
def process_inline(text):
"""Process inline markdown formatting."""
# Escape HTML first
# But we need to be careful not to double-escape
# Bold
text = re.sub(r'\*\*([^*]+)\*\*', r'<strong>\1</strong>', text)
# Italic
text = re.sub(r'\*([^*]+)\*', r'<em>\1</em>', text)
# Inline code (before links to avoid conflicts)
text = re.sub(r'`([^`]+)`', lambda m: f'<code>{html.escape(m.group(1))}</code>', text)
# Links
text = re.sub(r'\[([^\]]+)\]\(([^)]+)\)', r'<a href="\2">\1</a>', text)
# Checkmarks and X marks
text = text.replace('', '&#10003;')
text = text.replace('', '&#10007;')
return text
def slugify(text):
"""Convert text to URL-friendly slug."""
text = text.lower()
text = re.sub(r'[^a-z0-9\s-]', '', text)
text = re.sub(r'[\s]+', '-', text)
return text
def convert_file(md_path, html_path):
"""Convert a markdown file to HTML."""
print(f"Converting {os.path.basename(md_path)} -> {os.path.basename(html_path)}")
with open(md_path, 'r', encoding='utf-8') as f:
content = f.read()
# Extract title from first h1
title_match = re.search(r'^# (.+)$', content, re.MULTILINE)
title = title_match.group(1) if title_match else os.path.basename(md_path)
html_content = convert_md_to_html(content, title)
with open(html_path, 'w', encoding='utf-8') as f:
f.write(html_content)
def main():
docs_dir = '/home/camp/projects/powershell/docs'
md_files = [
'Update-ShopfloorPCs-Remote.md',
'Invoke-RemoteMaintenance.md',
'Update-PC-CompleteAsset.md',
'DATA_COLLECTION_PARITY.md',
'ShopDB-API.md'
]
for md_file in md_files:
md_path = os.path.join(docs_dir, md_file)
html_path = os.path.join(docs_dir, md_file.replace('.md', '.html'))
if os.path.exists(md_path):
convert_file(md_path, html_path)
else:
print(f"Warning: {md_path} not found")
print("\nConversion complete!")
print(f"HTML files saved to: {docs_dir}")
if __name__ == '__main__':
main()