diff --git a/api.asp b/api.asp index a57214c..399ff3f 100644 --- a/api.asp +++ b/api.asp @@ -115,6 +115,13 @@ Sub UpdateCompleteAsset() Dim hasWinRM hasWinRM = Trim(Request.Form("hasWinRM") & "") + ' Last boot time (optional) - accepts both lastBootUpTime and lastBootTime + Dim lastBootTime + lastBootTime = Trim(Request.Form("lastBootUpTime") & "") + If lastBootTime = "" Then + lastBootTime = Trim(Request.Form("lastBootTime") & "") + End If + ' DNC/GE registry data dncDualPathEnabled = Request.Form("dncDualPathEnabled") dncPath1Name = Trim(Request.Form("dncPath1Name") & "") @@ -290,7 +297,14 @@ Sub UpdateCompleteAsset() winrmValue = 0 End If - strSQL = "UPDATE machines SET serialnumber='" & safeSerial & "', modelnumberid=" & modelId & ", machinetypeid=" & machineTypeId & ", osid=" & osid & ", isvnc=" & vncValue & ", iswinrm=" & winrmValue & ", lastupdated=NOW() WHERE machineid=" & machineid + ' Build UPDATE with optional lastboottime + Dim lastBootPart + If lastBootTime <> "" Then + lastBootPart = ", lastboottime='" & Replace(lastBootTime, "'", "''") & "'" + Else + lastBootPart = "" + End If + strSQL = "UPDATE machines SET serialnumber='" & safeSerial & "', modelnumberid=" & modelId & ", machinetypeid=" & machineTypeId & ", osid=" & osid & ", isvnc=" & vncValue & ", iswinrm=" & winrmValue & lastBootPart & ", lastupdated=NOW() WHERE machineid=" & machineid objConn.Execute strSQL If Err.Number <> 0 Then SendError debugMsg & "10-UPDATE failed: " & Err.Description @@ -321,7 +335,16 @@ Sub UpdateCompleteAsset() winrmValueInsert = 0 End If - strSQL = "INSERT INTO machines (hostname, serialnumber, modelnumberid, machinetypeid, osid, machinestatusid, isvnc, iswinrm, lastupdated) VALUES ('" & safeHostname & "', '" & safeSerial & "', " & modelId & ", " & machineTypeId & ", " & osid & ", " & pcstatusid & ", " & vncValueInsert & ", " & winrmValueInsert & ", NOW())" + ' Build INSERT with optional lastboottime + Dim lastBootColInsert, lastBootValInsert + If lastBootTime <> "" Then + lastBootColInsert = ", lastboottime" + lastBootValInsert = ", '" & Replace(lastBootTime, "'", "''") & "'" + Else + lastBootColInsert = "" + lastBootValInsert = "" + End If + strSQL = "INSERT INTO machines (hostname, serialnumber, modelnumberid, machinetypeid, osid, machinestatusid, isvnc, iswinrm, lastupdated" & lastBootColInsert & ") VALUES ('" & safeHostname & "', '" & safeSerial & "', " & modelId & ", " & machineTypeId & ", " & osid & ", " & pcstatusid & ", " & vncValueInsert & ", " & winrmValueInsert & ", NOW()" & lastBootValInsert & ")" objConn.Execute strSQL If Err.Number <> 0 Then SendError debugMsg & "10-INSERT failed: " & Err.Description @@ -922,6 +945,14 @@ Function InsertOrUpdatePC(conn, hostname, serialnumber, manufacturer, model, pcT sqlStatusId = "NULL" End If + ' Build lastboottime part for UPDATE + Dim sqlLastBoot + If lastBootTime <> "" Then + sqlLastBoot = "lastboottime = '" & Replace(lastBootTime, "'", "''") & "', " + Else + sqlLastBoot = "" + End If + strSQL = "UPDATE machines SET " & _ "serialnumber = '" & safeSerial & "', " & _ "modelnumberid = " & sqlModelId & ", " & _ @@ -930,6 +961,7 @@ Function InsertOrUpdatePC(conn, hostname, serialnumber, manufacturer, model, pcT "machinenumber = " & sqlMachineNum & ", " & _ "osid = " & sqlOsId & ", " & _ "machinestatusid = " & sqlStatusId & ", " & _ + sqlLastBoot & _ "lastupdated = NOW() " & _ "WHERE machineid = " & CLng(machineid) & " AND pctypeid IS NOT NULL" @@ -967,7 +999,16 @@ Function InsertOrUpdatePC(conn, hostname, serialnumber, manufacturer, model, pcT ' Build SQL in parts to isolate error Dim sqlPart1, sqlPart2, sqlPart3 - sqlPart1 = "INSERT INTO machines (hostname, serialnumber, modelnumberid, machinetypeid, pctypeid, loggedinuser, machinenumber, osid, machinestatusid, isactive, lastupdated) VALUES (" + ' Add lastboottime column if provided + Dim sqlLastBootCol, sqlLastBootVal + If lastBootTime <> "" Then + sqlLastBootCol = ", lastboottime" + sqlLastBootVal = ", '" & Replace(lastBootTime, "'", "''") & "'" + Else + sqlLastBootCol = "" + sqlLastBootVal = "" + End If + sqlPart1 = "INSERT INTO machines (hostname, serialnumber, modelnumberid, machinetypeid, pctypeid, loggedinuser, machinenumber, osid, machinestatusid, isactive, lastupdated" & sqlLastBootCol & ") VALUES (" sqlPart2 = "'" & safeHostname & "', '" & safeSerial & "', " If modelId > 0 Then @@ -998,9 +1039,9 @@ Function InsertOrUpdatePC(conn, hostname, serialnumber, manufacturer, model, pcT End If If pcstatusid > 0 Then - sqlPart3 = sqlPart3 & CLng(pcstatusid) & ", 1, NOW())" + sqlPart3 = sqlPart3 & CLng(pcstatusid) & ", 1, NOW()" & sqlLastBootVal & ")" Else - sqlPart3 = sqlPart3 & "NULL, 1, NOW())" + sqlPart3 = sqlPart3 & "NULL, 1, NOW()" & sqlLastBootVal & ")" End If strSQL = sqlPart1 & sqlPart2 & sqlPart3 diff --git a/displaypcs.asp b/displaypcs.asp index 3dc54ce..4fd3188 100644 --- a/displaypcs.asp +++ b/displaypcs.asp @@ -39,11 +39,12 @@ <% -Dim currentPCStatus, recentFilter, deviceTypeFilter, pcTypeFilter, sel +Dim currentPCStatus, recentFilter, deviceTypeFilter, pcTypeFilter, uptimeFilter, sel currentPCStatus = Request.QueryString("pcstatus") recentFilter = Request.QueryString("recent") deviceTypeFilter = Request.QueryString("devicetype") pcTypeFilter = Request.QueryString("pctype") +uptimeFilter = Request.QueryString("uptime") ' Check for specialized PCs (CMM, Wax Trace, Measuring Tool) without equipment relationships Dim rsUnlinked, unlinkedCount @@ -110,7 +111,13 @@ Set rsStatus = Nothing - <% If currentPCStatus <> "" Or recentFilter <> "" Or deviceTypeFilter <> "" Or pcTypeFilter <> "" Or Request.QueryString("needsrelationship") <> "" Then %> + + <% If currentPCStatus <> "" Or recentFilter <> "" Or deviceTypeFilter <> "" Or pcTypeFilter <> "" Or uptimeFilter <> "" Or Request.QueryString("needsrelationship") <> "" Then %> Clear @@ -129,6 +136,7 @@ Set rsStatus = Nothing Model OS Equipment + Uptime VNC WinRM @@ -137,17 +145,19 @@ Set rsStatus = Nothing <% ' Build query based on filters - Dim pcStatusFilter, recentDaysFilter, deviceTypeFilterSQL, pcTypeFilterSQL, needsRelationshipFilter, whereClause - Dim displayName, hasVnc, vncHost, hasWinrm + Dim pcStatusFilter, recentDaysFilter, deviceTypeFilterSQL, pcTypeFilterSQL, uptimeFilterSQL, needsRelationshipFilter, whereClause + Dim displayName, hasVnc, vncHost, hasWinrm, uptimeDays pcStatusFilter = Request.QueryString("pcstatus") recentDaysFilter = Request.QueryString("recent") deviceTypeFilterSQL = Request.QueryString("devicetype") pcTypeFilterSQL = Request.QueryString("pctype") + uptimeFilterSQL = Request.QueryString("uptime") needsRelationshipFilter = Request.QueryString("needsrelationship") ' Base query with LEFT JOINs to show all PCs strSQL = "SELECT m.machineid, m.hostname, m.serialnumber, m.machinenumber, m.machinestatusid, " & _ - "m.modelnumberid, m.osid, m.loggedinuser, m.lastupdated, m.isvnc, m.iswinrm, " & _ + "m.modelnumberid, m.osid, m.loggedinuser, m.lastupdated, m.isvnc, m.iswinrm, m.lastboottime, " & _ + "DATEDIFF(NOW(), m.lastboottime) AS uptime_days, " & _ "vendors.vendor, models.modelnumber, operatingsystems.operatingsystem, " & _ "c.address AS ipaddress, c.macaddress, " & _ "machinestatus.machinestatus, " & _ @@ -184,6 +194,11 @@ Set rsStatus = Nothing whereClause = whereClause & " AND m.pctypeid = " & pcTypeFilterSQL End If + ' Filter by uptime (days since last boot) + If uptimeFilterSQL <> "" And IsNumeric(uptimeFilterSQL) Then + whereClause = whereClause & " AND m.lastboottime IS NOT NULL AND DATEDIFF(NOW(), m.lastboottime) > " & uptimeFilterSQL + End If + ' Filter for specialized PCs needing equipment relationships If needsRelationshipFilter = "1" Then whereClause = whereClause & " AND m.pctypeid = 7" & _ @@ -216,6 +231,23 @@ Set rsStatus = Nothing Response.Write("-") End If %> + <% + ' Uptime column - show days since last boot + If Not IsNull(rs("uptime_days")) And rs("uptime_days") <> "" Then + uptimeDays = CLng(rs("uptime_days") & "") + If uptimeDays > 90 Then + Response.Write("" & uptimeDays & "d") + ElseIf uptimeDays > 30 Then + Response.Write("" & uptimeDays & "d") + ElseIf uptimeDays > 7 Then + Response.Write("" & uptimeDays & "d") + Else + Response.Write("" & uptimeDays & "d") + End If + Else + Response.Write("-") + End If + %> <% ' VNC column with link hasVnc = False diff --git a/scripts/Update-PC-Minimal.ps1 b/scripts/Update-PC-Minimal.ps1 index 58dcc43..541ad77 100644 --- a/scripts/Update-PC-Minimal.ps1 +++ b/scripts/Update-PC-Minimal.ps1 @@ -81,11 +81,17 @@ if ($interfaces.Count -gt 0) { $data.networkInterfaces = ($interfaces | ConvertTo-Json -Compress) } -# Try to get OS +# Try to get OS and last boot time try { $os = Get-CimInstance -ClassName Win32_OperatingSystem -ErrorAction Stop $data.osVersion = $os.Caption "OS: $($data.osVersion)" | Tee-Object -FilePath $logFile -Append + + # Get last boot time + if ($os.LastBootUpTime) { + $data.lastBootUpTime = $os.LastBootUpTime.ToString("yyyy-MM-dd HH:mm:ss") + "Last Boot: $($data.lastBootUpTime)" | Tee-Object -FilePath $logFile -Append + } } catch { "ERROR getting OS: $_" | Tee-Object -FilePath $logFile -Append } diff --git a/scripts/Update-ShopfloorPCs-Remote.ps1 b/scripts/Update-ShopfloorPCs-Remote.ps1 index 14a5df1..e579f0c 100644 --- a/scripts/Update-ShopfloorPCs-Remote.ps1 +++ b/scripts/Update-ShopfloorPCs-Remote.ps1 @@ -327,6 +327,7 @@ function Get-RemotePCInfo { $result.Model = $computerSystem.Model $result.LoggedInUser = $computerSystem.UserName $result.OSVersion = $os.Caption + $result.LastBootUpTime = if ($os.LastBootUpTime) { $os.LastBootUpTime.ToString("yyyy-MM-dd HH:mm:ss") } else { $null } # Get network interfaces $networkAdapters = Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration | @@ -692,6 +693,11 @@ function Send-PCDataToApi { osVersion = $PCData.OSVersion } + # Add last boot time if available + if ($PCData.LastBootUpTime) { + $postData.lastBootUpTime = $PCData.LastBootUpTime + } + # Add machine number if available if ($PCData.MachineNo) { $postData.machineNo = $PCData.MachineNo diff --git a/sql/add_lastboottime_column.sql b/sql/add_lastboottime_column.sql new file mode 100644 index 0000000..f570c0c --- /dev/null +++ b/sql/add_lastboottime_column.sql @@ -0,0 +1,29 @@ +-- Add lastboottime column to machines table for PC uptime tracking +-- Run on production database +-- Date: 2025-12-09 + +-- Check if column exists before adding +SET @dbname = DATABASE(); +SET @tablename = 'machines'; +SET @columnname = 'lastboottime'; +SET @preparedStatement = (SELECT IF( + ( + SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_SCHEMA = @dbname + AND TABLE_NAME = @tablename + AND COLUMN_NAME = @columnname + ) > 0, + 'SELECT ''Column lastboottime already exists'';', + 'ALTER TABLE machines ADD COLUMN lastboottime DATETIME NULL DEFAULT NULL AFTER lastupdated;' +)); + +PREPARE alterIfNotExists FROM @preparedStatement; +EXECUTE alterIfNotExists; +DEALLOCATE PREPARE alterIfNotExists; + +-- Verify the column was added +SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_DEFAULT +FROM INFORMATION_SCHEMA.COLUMNS +WHERE TABLE_SCHEMA = DATABASE() +AND TABLE_NAME = 'machines' +AND COLUMN_NAME = 'lastboottime';