Files
powershell-scripts/winrm-setup-package/WinRM-Setup-Guide.html
cproudlock 86b32d8597 Add fixnetworkshare, winrm-setup-package, udc remote-execution suites
- NetworkDriveManager.ps1: S: drive repair utility
- winrm-setup-package: Invoke-RemoteTask helper + Setup-WinRM.bat + HTML guide
- remote-execution/udc: UDC_Update.ps1 and batch wrappers for updating
  DNC controllers on shop-floor PCs
- Invoke-RemoteMaintenance.ps1: substantial rework (~1650 lines)
- Schedule-Maintenance and complete-asset minor updates
- Bump edncfix gitlink to v1.6.0 (2748bfa)
- .gitignore: block inventory.csv/xlsx (CUI) and logs_*.txt (per-host logs)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 12:04:40 -04:00

425 lines
16 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WinRM Setup Package for Shopfloor PCs</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;
background: #f5f5f5;
color: #333;
}
h1 {
color: #0078d4;
border-bottom: 3px solid #0078d4;
padding-bottom: 10px;
}
h2 {
color: #106ebe;
border-bottom: 1px solid #ddd;
padding-bottom: 5px;
margin-top: 30px;
}
h3 {
color: #333;
margin-top: 25px;
}
code {
background: #e8e8e8;
padding: 2px 6px;
border-radius: 3px;
font-family: 'Consolas', 'Courier New', monospace;
font-size: 0.9em;
}
pre {
background: #1e1e1e;
color: #d4d4d4;
padding: 15px;
border-radius: 5px;
overflow-x: auto;
font-family: 'Consolas', 'Courier New', monospace;
font-size: 0.85em;
line-height: 1.4;
}
pre code {
background: none;
padding: 0;
color: inherit;
}
table {
width: 100%;
border-collapse: collapse;
margin: 15px 0;
background: white;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}
th, td {
padding: 10px 12px;
text-align: left;
border: 1px solid #ddd;
}
th {
background: #0078d4;
color: white;
font-weight: 600;
}
tr:nth-child(even) { background: #f9f9f9; }
tr:hover { background: #f0f7ff; }
hr {
border: none;
border-top: 1px solid #ddd;
margin: 30px 0;
}
.warning {
background: #fff3cd;
border-left: 4px solid #ffc107;
padding: 10px 15px;
margin: 15px 0;
}
.info {
background: #e7f3ff;
border-left: 4px solid #0078d4;
padding: 10px 15px;
margin: 15px 0;
}
ol, ul { padding-left: 25px; }
li { margin: 5px 0; }
.toc {
background: white;
padding: 15px 20px;
border-radius: 5px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
margin-bottom: 30px;
}
.toc h3 { margin-top: 0; }
.toc ul { list-style: none; padding-left: 0; }
.toc li { margin: 8px 0; }
.toc a { color: #0078d4; text-decoration: none; }
.toc a:hover { text-decoration: underline; }
.comment { color: #6a9955; }
.string { color: #ce9178; }
.keyword { color: #569cd6; }
</style>
</head>
<body>
<h1>WinRM Setup Package for Shopfloor PCs</h1>
<p>This package provides scripts to configure WinRM (Windows Remote Management) on shopfloor PCs and execute remote maintenance tasks.</p>
<div class="toc">
<h3>Contents</h3>
<ul>
<li><a href="#quick-start">Quick Start</a></li>
<li><a href="#setup-details">Setup Script Details</a></li>
<li><a href="#tasks">Available Remote Tasks</a></li>
<li><a href="#troubleshooting">Troubleshooting</a></li>
<li><a href="#security">Security Considerations</a></li>
<li><a href="#custom-tasks">Adding Custom Tasks</a></li>
</ul>
</div>
<h2>Package Contents</h2>
<table>
<tr><th>File</th><th>Description</th></tr>
<tr><td><code>Setup-WinRM.bat</code></td><td>Run on each PC to enable and configure WinRM</td></tr>
<tr><td><code>Invoke-RemoteTask.ps1</code></td><td>PowerShell script to execute tasks on remote PCs</td></tr>
<tr><td><code>hosts.txt</code></td><td>List of target computers (edit before use)</td></tr>
<tr><td><code>WinRM-Setup-Guide.html</code></td><td>This documentation</td></tr>
</table>
<hr>
<h2 id="quick-start">Quick Start</h2>
<h3>Step 1: Configure Your Admin Workstation</h3>
<p>Before connecting to remote PCs, run this <strong>once</strong> on your admin workstation (as Administrator):</p>
<pre><code>Set-Item WSMan:\localhost\Client\TrustedHosts -Value <span class="string">"*.logon.ds.ge.com"</span> -Force</code></pre>
<p>This allows your workstation to connect to any PC in the domain.</p>
<h3>Step 2: Configure the Setup Script</h3>
<p>Edit <code>Setup-WinRM.bat</code> and update these values at the top:</p>
<pre><code><span class="comment">REM Default security group - who can use WinRM to connect</span>
set "DEFAULT_SECURITY_GROUP=<span class="string">logon\groupid</span>"
<span class="comment">REM Where to log the inventory CSV (network share recommended)</span>
set "DEFAULT_LOG_PATH=<span class="string">\\server\share\winrm-inventory</span>"
<span class="comment">REM Domain suffix for TrustedHosts</span>
set "TRUSTED_DOMAIN=<span class="string">*.logon.ds.ge.com</span>"
<span class="comment">REM Optional: Trust a specific subnet (uncomment and set)</span>
<span class="comment">REM set "TRUSTED_SUBNET=10.48.130.*"</span></code></pre>
<h3>Step 3: Create Security Group in Active Directory</h3>
<ol>
<li>Open <strong>Active Directory Users and Computers</strong></li>
<li>Create a new Security Group (or use existing group matching <code>groupid</code>)</li>
<li>Add users who should have remote management access</li>
</ol>
<h3>Step 4: Run Setup on Each Shopfloor PC</h3>
<p>Run as Administrator on each PC:</p>
<pre><code>Setup-WinRM.bat</code></pre>
<p>Or with parameters:</p>
<pre><code>Setup-WinRM.bat "logon\groupid" "\\server\share\winrm-inventory"</code></pre>
<p>The script will:</p>
<ul>
<li>Enable WinRM service</li>
<li>Configure authentication (Negotiate/Kerberos)</li>
<li>Set firewall rules (domain profile only)</li>
<li>Restrict access to the security group</li>
<li>Log hostname/IP to CSV inventory</li>
</ul>
<h3>Step 5: Run Remote Tasks</h3>
<p>From your admin workstation, edit <code>hosts.txt</code> with target PCs, then:</p>
<pre><code><span class="comment"># Test connectivity</span>
.\Invoke-RemoteTask.ps1 -Task TestConnection
<span class="comment"># Restart print spooler on all hosts</span>
.\Invoke-RemoteTask.ps1 -Task RestartSpooler
<span class="comment"># Check disk space</span>
.\Invoke-RemoteTask.ps1 -Task GetDiskSpace
<span class="comment"># Run on a single PC</span>
.\Invoke-RemoteTask.ps1 -ComputerName <span class="string">"PC001"</span> -Task FlushDNS</code></pre>
<hr>
<h2 id="setup-details">Setup Script Details</h2>
<h3>What Setup-WinRM.bat Configures</h3>
<table>
<tr><th>Setting</th><th>Value</th><th>Purpose</th></tr>
<tr><td>WinRM Service</td><td>Auto-start</td><td>Ensures WinRM starts on boot</td></tr>
<tr><td>AllowUnencrypted</td><td>false</td><td>Security: require encrypted connections</td></tr>
<tr><td>Negotiate Auth</td><td>true</td><td>Enables Kerberos/NTLM authentication</td></tr>
<tr><td>CredSSP Auth</td><td>true</td><td>Enables credential delegation (double-hop)</td></tr>
<tr><td>Firewall</td><td>Domain profile</td><td>Opens port 5985 for domain connections only</td></tr>
<tr><td>TrustedHosts</td><td>*.logon.ds.ge.com</td><td>Trusts domain-joined PCs</td></tr>
<tr><td>RootSDDL</td><td>Security group</td><td>Restricts who can connect</td></tr>
</table>
<h3>CSV Inventory</h3>
<p>The setup script logs each PC to a CSV file:</p>
<pre><code>Hostname,IPAddress,SetupDate,OSVersion,SecurityGroup
PC001,10.48.130.101,2026-01-08 09:30:00,10.0,logon\groupid
PC002,10.48.130.102,2026-01-08 09:35:00,10.0,logon\groupid</code></pre>
<p>You can use this CSV as your hosts file:</p>
<pre><code><span class="comment"># Extract hostnames from CSV</span>
Import-Csv <span class="string">"\\server\share\winrm-inventory\winrm-inventory.csv"</span> |
Select-Object -ExpandProperty Hostname |
Set-Content .\hosts.txt</code></pre>
<hr>
<h2 id="tasks">Available Remote Tasks</h2>
<table>
<tr><th>Task</th><th>Description</th></tr>
<tr><td><code>TestConnection</code></td><td>Verify WinRM connectivity</td></tr>
<tr><td><code>GetUptime</code></td><td>Show system uptime and last boot time</td></tr>
<tr><td><code>GetDiskSpace</code></td><td>Show free space on all drives</td></tr>
<tr><td><code>RestartSpooler</code></td><td>Restart Print Spooler service</td></tr>
<tr><td><code>FlushDNS</code></td><td>Clear DNS resolver cache</td></tr>
<tr><td><code>ClearTempFiles</code></td><td>Delete Windows temp files</td></tr>
<tr><td><code>DiskCleanup</code></td><td>Run Windows Disk Cleanup</td></tr>
<tr><td><code>OptimizeDisk</code></td><td>TRIM (SSD) or Defrag (HDD)</td></tr>
<tr><td><code>SyncTime</code></td><td>Force time sync with domain controller</td></tr>
<tr><td><code>RestartService</code></td><td>Restart any Windows service (requires <code>-ServiceName</code>)</td></tr>
<tr><td><code>RunCommand</code></td><td>Run custom PowerShell command (requires <code>-Command</code>)</td></tr>
<tr><td><code>RestartComputer</code></td><td>Restart the remote PC (requires YES confirmation)</td></tr>
</table>
<h3>Examples</h3>
<pre><code><span class="comment"># Check uptime on all hosts</span>
.\Invoke-RemoteTask.ps1 -Task GetUptime
<span class="comment"># Restart a specific service</span>
.\Invoke-RemoteTask.ps1 -Task RestartService -ServiceName <span class="string">"Spooler"</span>
<span class="comment"># Run custom command</span>
.\Invoke-RemoteTask.ps1 -Task RunCommand -Command <span class="string">"Get-Process | Sort CPU -Desc | Select -First 5"</span>
<span class="comment"># Use custom hosts file</span>
.\Invoke-RemoteTask.ps1 -HostsFile <span class="string">".\cnc-machines.txt"</span> -Task FlushDNS
<span class="comment"># Specify DNS suffix for short hostnames</span>
.\Invoke-RemoteTask.ps1 -DnsSuffix <span class="string">"logon.ds.ge.com"</span> -Task TestConnection
<span class="comment"># Restart a remote PC (will prompt for confirmation)</span>
.\Invoke-RemoteTask.ps1 -ComputerName <span class="string">"PC001"</span> -Task RestartComputer
<span class="comment"># Increase parallelism for faster execution on many PCs</span>
.\Invoke-RemoteTask.ps1 -Task FlushDNS -ThrottleLimit 20
<span class="comment"># Save results to a log file</span>
.\Invoke-RemoteTask.ps1 -Task GetDiskSpace -LogResults</code></pre>
<h3>Targeting Multiple PCs</h3>
<pre><code><span class="comment"># Comma-separated list</span>
.\Invoke-RemoteTask.ps1 -ComputerName <span class="string">"PC001"</span>,<span class="string">"PC002"</span>,<span class="string">"PC003"</span> -Task GetUptime
<span class="comment"># Array variable</span>
$pcs = @(<span class="string">"PC001"</span>, <span class="string">"PC002"</span>, <span class="string">"PC003"</span>)
.\Invoke-RemoteTask.ps1 -ComputerName $pcs -Task FlushDNS
<span class="comment"># From hosts.txt file (default)</span>
.\Invoke-RemoteTask.ps1 -Task RestartSpooler
<span class="comment"># From CSV inventory</span>
$pcs = (Import-Csv <span class="string">"\\server\share\winrm-inventory.csv"</span>).Hostname
.\Invoke-RemoteTask.ps1 -ComputerName $pcs -Task GetDiskSpace
<span class="comment"># From Active Directory query</span>
$pcs = (Get-ADComputer -Filter <span class="string">"Name -like 'SHOPFLOOR-*'"</span>).Name
.\Invoke-RemoteTask.ps1 -ComputerName $pcs -Task SyncTime</code></pre>
<div class="info">
<strong>Parallel Execution:</strong> All commands run in parallel (default: 10 concurrent connections). Adjust with <code>-ThrottleLimit</code> parameter.
</div>
<h3>Logging Results</h3>
<p>Use <code>-LogResults</code> to save task output to a timestamped log file in the script directory:</p>
<pre><code>.\Invoke-RemoteTask.ps1 -Task RestartSpooler -LogResults
<span class="comment"># Creates: RemoteTask_20260108_143022.log</span></code></pre>
<p>Log files contain:</p>
<ul>
<li>Task name and parameters</li>
<li>Execution time</li>
<li>Status of each computer (OK/FAIL)</li>
<li>Result messages</li>
<li>Summary totals</li>
</ul>
<hr>
<h2 id="troubleshooting">Troubleshooting</h2>
<h3>"Access Denied" when connecting</h3>
<ol>
<li>Verify you're a member of the WinRM security group</li>
<li>Check that your credentials are correct</li>
<li>Verify the target PC ran Setup-WinRM.bat successfully</li>
</ol>
<h3>"WinRM cannot complete the operation"</h3>
<ol>
<li>Verify the target PC is reachable: <code>ping PC001</code></li>
<li>Check WinRM is running on target: <code>sc query winrm</code> (on target PC)</li>
<li>Verify firewall allows port 5985</li>
</ol>
<h3>"The WinRM client cannot process the request"</h3>
<p>Add target to TrustedHosts on your admin workstation:</p>
<pre><code>Set-Item WSMan:\localhost\Client\TrustedHosts -Value <span class="string">"*.logon.ds.ge.com"</span> -Force</code></pre>
<h3>Test WinRM Configuration</h3>
<p>On your admin workstation:</p>
<pre><code><span class="comment"># Test basic connectivity</span>
Test-WSMan -ComputerName PC001
<span class="comment"># Test with credentials</span>
$cred = Get-Credential
Test-WSMan -ComputerName PC001 -Credential $cred -Authentication Negotiate
<span class="comment"># Enter interactive session</span>
Enter-PSSession -ComputerName PC001 -Credential $cred -Authentication Negotiate</code></pre>
<p>On the target PC:</p>
<pre><code>winrm enumerate winrm/config/listener
winrm get winrm/config/service</code></pre>
<hr>
<h2 id="security">Security Considerations</h2>
<div class="warning">
<strong>Important Security Notes:</strong>
</div>
<ol>
<li><strong>Use Security Groups</strong>: Always restrict WinRM access to a specific AD group</li>
<li><strong>Domain Profile Only</strong>: Firewall rules only allow connections on domain networks</li>
<li><strong>No Unencrypted Traffic</strong>: AllowUnencrypted is set to false</li>
<li><strong>Audit Access</strong>: Enable Windows Security auditing for logon events</li>
<li><strong>Credential Protection</strong>: Use dedicated admin accounts, not personal accounts</li>
</ol>
<hr>
<h2 id="custom-tasks">Adding Custom Tasks</h2>
<p>Edit <code>Invoke-RemoteTask.ps1</code> and add to the <code>$TaskScripts</code> hashtable:</p>
<pre><code><span class="string">'MyCustomTask'</span> = {
$result = @{
Success = <span class="keyword">$false</span>
Hostname = $env:COMPUTERNAME
Output = <span class="string">""</span>
Error = <span class="keyword">$null</span>
}
<span class="keyword">try</span> {
<span class="comment"># Your code here</span>
$result.Output = <span class="string">"Task completed"</span>
$result.Success = <span class="keyword">$true</span>
} <span class="keyword">catch</span> {
$result.Error = $_.Exception.Message
}
<span class="keyword">return</span> $result
}</code></pre>
<p>Then add the task name to the <code>ValidateSet</code> in the param block.</p>
<hr>
<h2>Support</h2>
<p>For issues or questions, contact your IT support team.</p>
<p style="text-align: center; color: #666; margin-top: 40px; font-size: 0.9em;">
WinRM Setup Package &copy; 2026 | Generated from README.md
</p>
</body>
</html>