Add scheduled maintenance, PC list export, and subnet scanner scripts

- Schedule-Maintenance.ps1: DPAPI credential storage + Task Scheduler integration
- Export-PCList.ps1: Pull PC lists from ShopDB API with type/BU filtering
- Find-ShopfloorPCs.ps1: Parallel subnet scanner with WinRM and DNS checks
- INSTRUCTIONS.txt: Schedule-Maintenance.ps1 documentation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
cproudlock
2026-02-19 14:58:18 -05:00
parent 7d3519f613
commit 847ec402bd
4 changed files with 797 additions and 0 deletions

View File

@@ -0,0 +1,223 @@
<#
.SYNOPSIS
Queries ShopDB API and exports a computer list for Invoke-RemoteMaintenance.ps1.
.DESCRIPTION
Pulls shopfloor PC data from the ShopDB API and writes a text file
(one hostname per line) compatible with:
Invoke-RemoteMaintenance.ps1 -ComputerListFile "shopfloor-pcs.txt"
Can filter by PC type, business unit, or export all.
.PARAMETER PcType
Filter by PC type. Omit for all types.
.PARAMETER BusinessUnit
Filter by business unit. Omit for all BUs.
.PARAMETER OutputFile
Output file path (default: shopfloor-pcs.txt in script directory).
.PARAMETER ApiUrl
ShopDB API URL.
.PARAMETER IncludeDetails
Add IP, PC type, and business unit as comments in the output.
.EXAMPLE
.\Export-PCList.ps1
# Export all shopfloor PCs
.EXAMPLE
.\Export-PCList.ps1 -PcType Dashboard
# Export only Dashboard PCs
.EXAMPLE
.\Export-PCList.ps1 -BusinessUnit Blisk -OutputFile "blisk-pcs.txt"
.EXAMPLE
.\Export-PCList.ps1 -PcType Dashboard,Shopfloor -BusinessUnit Blisk,HPT
# Multiple filters (OR logic within each, AND between type/BU)
#>
[CmdletBinding()]
param(
[ValidateSet('Standard','Engineer','Shopfloor','CMM','Wax / Trace','Keyence',
'Genspect','Heat Treat','Inspection','Dashboard','Lobby Display','Uncategorized')]
[string[]]$PcType,
[ValidateSet('TBD','Blisk','HPT','Spools','Inspection','Venture','Turn/Burn','DT')]
[string[]]$BusinessUnit,
[string]$OutputFile,
[string]$ApiUrl = "https://tsgwp00525.rd.ds.ge.com/shopdb/api.asp",
[switch]$IncludeDetails
)
# ---------------------------------------------------------------------------
# Lookup tables (match IDs in ShopDB)
# ---------------------------------------------------------------------------
$PcTypeLookup = @{
'Standard' = 1; 'Engineer' = 2; 'Shopfloor' = 3; 'Uncategorized' = 4;
'CMM' = 5; 'Wax / Trace' = 6; 'Keyence' = 7; 'Genspect' = 8;
'Heat Treat' = 9; 'Inspection' = 10; 'Dashboard' = 11; 'Lobby Display' = 12
}
$PcTypeReverse = @{}
$PcTypeLookup.GetEnumerator() | ForEach-Object { $PcTypeReverse[$_.Value] = $_.Key }
$BusinessUnitLookup = @{
'TBD' = 1; 'Blisk' = 2; 'HPT' = 3; 'Spools' = 4;
'Inspection' = 5; 'Venture' = 6; 'Turn/Burn' = 7; 'DT' = 8
}
$BusinessUnitReverse = @{}
$BusinessUnitLookup.GetEnumerator() | ForEach-Object { $BusinessUnitReverse[$_.Value] = $_.Key }
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
function Write-Status {
param([string]$Message, [string]$Level = "INFO")
$timestamp = Get-Date -Format "HH:mm:ss"
$color = switch ($Level) {
"OK" { "Green" }
"WARN" { "Yellow" }
"ERROR" { "Red" }
default { "Cyan" }
}
Write-Host "[$timestamp] [$Level] $Message" -ForegroundColor $color
}
function Get-ShopfloorPCsFromApi {
param(
[string]$Url,
[int]$PcTypeId = 0,
[int]$BusinessUnitId = 0
)
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$queryParams = "action=getShopfloorPCs"
if ($PcTypeId -gt 0) {
$queryParams += "&pctypeid=$PcTypeId"
}
if ($BusinessUnitId -gt 0) {
$queryParams += "&businessunitid=$BusinessUnitId"
}
$fullUrl = "$Url`?$queryParams"
$webClient = New-Object System.Net.WebClient
$json = $webClient.DownloadString($fullUrl)
$response = $json | ConvertFrom-Json
if ($response.success -and $response.data) {
return $response.data
}
return @()
}
# ---------------------------------------------------------------------------
# Default output path
# ---------------------------------------------------------------------------
if (-not $OutputFile) {
$OutputFile = Join-Path $PSScriptRoot "shopfloor-pcs.txt"
}
# ---------------------------------------------------------------------------
# Query API
# ---------------------------------------------------------------------------
Write-Status "Querying ShopDB API..."
try {
$allPCs = Get-ShopfloorPCsFromApi -Url $ApiUrl
} catch {
Write-Status "Failed to query API: $_" -Level "ERROR"
exit 1
}
if ($allPCs.Count -eq 0) {
Write-Status "API returned no PCs." -Level "ERROR"
exit 1
}
Write-Status "API returned $($allPCs.Count) total PCs" -Level "OK"
# ---------------------------------------------------------------------------
# Filter
# ---------------------------------------------------------------------------
$filtered = $allPCs
if ($PcType) {
$typeIds = $PcType | ForEach-Object { $PcTypeLookup[$_] }
$filtered = $filtered | Where-Object { $_.pctypeid -in $typeIds }
Write-Status "Filtered to PC types: $($PcType -join ', ') -> $($filtered.Count) PCs"
}
if ($BusinessUnit) {
$buIds = $BusinessUnit | ForEach-Object { $BusinessUnitLookup[$_] }
$filtered = $filtered | Where-Object { $_.businessunitid -in $buIds }
Write-Status "Filtered to business units: $($BusinessUnit -join ', ') -> $($filtered.Count) PCs"
}
$filtered = @($filtered | Where-Object { $_.hostname })
if ($filtered.Count -eq 0) {
Write-Status "No PCs match the selected filters." -Level "WARN"
exit 0
}
# Sort by hostname
$filtered = $filtered | Sort-Object hostname
# ---------------------------------------------------------------------------
# Write output
# ---------------------------------------------------------------------------
$lines = [System.Collections.Generic.List[string]]::new()
$lines.Add("# Shopfloor PC List - Generated $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')")
$lines.Add("# Source: ShopDB API")
if ($PcType) {
$lines.Add("# PC Type filter: $($PcType -join ', ')")
}
if ($BusinessUnit) {
$lines.Add("# Business Unit filter: $($BusinessUnit -join ', ')")
}
$lines.Add("# Total: $($filtered.Count) PCs")
$lines.Add("# Usage: .\Invoke-RemoteMaintenance.ps1 -ComputerListFile `"$OutputFile`" -Task Reboot")
$lines.Add("")
foreach ($pc in $filtered) {
if ($IncludeDetails) {
$typeName = $PcTypeReverse[[int]$pc.pctypeid]
$buName = $BusinessUnitReverse[[int]$pc.businessunitid]
$ip = if ($pc.ipaddress) { $pc.ipaddress } else { "no IP" }
$lines.Add("$($pc.hostname) # $ip | $typeName | $buName")
} else {
$lines.Add($pc.hostname)
}
}
$lines | Out-File -FilePath $OutputFile -Encoding UTF8
Write-Status "Wrote $($filtered.Count) PCs to: $OutputFile" -Level "OK"
# ---------------------------------------------------------------------------
# Summary
# ---------------------------------------------------------------------------
Write-Host ""
Write-Host "=== PC LIST ===" -ForegroundColor White
# Group by type for summary
$byType = $filtered | Group-Object pctypeid | Sort-Object Name
foreach ($group in $byType) {
$typeName = $PcTypeReverse[[int]$group.Name]
if (-not $typeName) { $typeName = "Unknown ($($group.Name))" }
Write-Host " $($typeName): $($group.Count)" -ForegroundColor Gray
}
Write-Host ""
Write-Host "Output file: $OutputFile" -ForegroundColor Green
Write-Host "Next step: .\Invoke-RemoteMaintenance.ps1 -ComputerListFile `"$OutputFile`" -Task Reboot" -ForegroundColor Yellow