Add SAGE-SQL session manager app, shared work items board, update session log
- Session manager: self-service RDP session reset for Dataforth users (Default.aspx + web.config) - WORKITEMS.md: shared task board for Mike/Howard with @tagging, syncs via Gitea - Session log: deployment deferred due to VPN connectivity issues Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
38
WORKITEMS.md
Normal file
38
WORKITEMS.md
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
# Shared Work Items
|
||||||
|
|
||||||
|
Tag yourself to claim. Check off when done. Add new items at the bottom of the relevant section.
|
||||||
|
|
||||||
|
**Syntax:** `- [ ] Description — @mike/@howard/@unassigned | added YYYY-MM-DD`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Active
|
||||||
|
|
||||||
|
- [ ] Deploy session manager to SAGE-SQL (IIS app, Windows Auth) — files ready at `clients/dataforth/session-manager/` — @mike | added 2026-04-17
|
||||||
|
- [ ] Cascades Synology (cascadesds) — get admin creds, add to vault — @howard | added 2026-04-17
|
||||||
|
- [ ] Howard Gitea account — create via web UI at git.azcomputerguru.com — @mike | added 2026-04-16
|
||||||
|
- [ ] desertrat.com — add DMARC p=reject + harden SPF on Route 53 (need AWS access) — @unassigned | added 2026-04-17
|
||||||
|
- [ ] desertrat.com — long-term migration from WebSvr to IX + MailProtector — @unassigned | added 2026-04-17
|
||||||
|
- [ ] MVAN other domains — only mvaninc.com has DMARC; client has other domains needing protection — @unassigned | added 2026-04-17
|
||||||
|
- [ ] Glaztech Syncro ticket #32165 — timer entry billed wrong (should be comment+time); fix in Syncro GUI — @mike | added 2026-04-17
|
||||||
|
- [ ] jparkinsonaz.com certbot — retry autodiscover cert once A record TTL expires — @unassigned | added 2026-04-17
|
||||||
|
- [ ] Neptune jparkinson password — set to jP$48504850, verify mail working — @unassigned | added 2026-04-17
|
||||||
|
- [ ] Len's Auto Brokerage — deploy GuruRMM v0.6.1 to 10 Windows endpoints — @mike | added 2026-04-16
|
||||||
|
- [ ] GuruRMM server migration 5 — sqlx checksum drift blocks new server build — @mike | added 2026-04-16
|
||||||
|
- [ ] Jupiter Windows VM — Server 2022 build worker for MSI CI — @unassigned | added 2026-04-16
|
||||||
|
- [ ] Cloudflare SXG — disable via dashboard (API tokens lack scope), auto-removes June 23 — @unassigned | added 2026-04-17
|
||||||
|
- [ ] GrepAI index — run `grepai watch` to build semantic search index — @unassigned | added 2026-04-16
|
||||||
|
|
||||||
|
## Completed
|
||||||
|
|
||||||
|
_Move items here when done. Keep for 30 days then delete._
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## How to use
|
||||||
|
|
||||||
|
- **Claim:** change `@unassigned` to your name
|
||||||
|
- **Add:** append to Active section with today's date
|
||||||
|
- **Complete:** move to Completed with date: `- [x] Description — @mike | done 2026-04-18`
|
||||||
|
- **Claude:** say "show work items" or "add work item: ..." and Claude reads/updates this file
|
||||||
|
- **Sync:** items sync via `/sync` like everything else
|
||||||
381
clients/dataforth/session-manager/Default.aspx
Normal file
381
clients/dataforth/session-manager/Default.aspx
Normal file
@@ -0,0 +1,381 @@
|
|||||||
|
<%@ Page Language="C#" AutoEventWireup="true" %>
|
||||||
|
<%@ Import Namespace="System.Diagnostics" %>
|
||||||
|
<%@ Import Namespace="System.Text.RegularExpressions" %>
|
||||||
|
<%@ Import Namespace="System.Collections.Generic" %>
|
||||||
|
<%@ Import Namespace="System.Web.Security" %>
|
||||||
|
<script runat="server">
|
||||||
|
public class SessionInfo
|
||||||
|
{
|
||||||
|
public string SessionName { get; set; }
|
||||||
|
public string Username { get; set; }
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string State { get; set; }
|
||||||
|
public bool CanReset { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private string currentUser;
|
||||||
|
private string currentDisplayName;
|
||||||
|
private List<SessionInfo> userSessions = new List<SessionInfo>();
|
||||||
|
private string statusMessage = "";
|
||||||
|
private string statusClass = "";
|
||||||
|
|
||||||
|
protected void Page_Load(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
currentUser = Context.User.Identity.Name;
|
||||||
|
// Strip domain prefix
|
||||||
|
if (currentUser.Contains("\\"))
|
||||||
|
currentUser = currentUser.Split('\\')[1];
|
||||||
|
currentDisplayName = currentUser;
|
||||||
|
|
||||||
|
// Handle reset action
|
||||||
|
string resetId = Request.QueryString["reset"];
|
||||||
|
if (!string.IsNullOrEmpty(resetId))
|
||||||
|
{
|
||||||
|
int sessionId;
|
||||||
|
if (int.TryParse(resetId, out sessionId))
|
||||||
|
{
|
||||||
|
// Verify the session belongs to this user before resetting
|
||||||
|
var sessions = GetSessions();
|
||||||
|
var target = sessions.Find(s => s.Id == sessionId &&
|
||||||
|
s.Username.Equals(currentUser, StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
|
if (target != null && target.State == "Disc")
|
||||||
|
{
|
||||||
|
RunCommand("logoff " + sessionId);
|
||||||
|
LogAction(currentUser, sessionId, "reset");
|
||||||
|
statusMessage = "Session #" + sessionId + " has been reset.";
|
||||||
|
statusClass = "success";
|
||||||
|
}
|
||||||
|
else if (target != null)
|
||||||
|
{
|
||||||
|
statusMessage = "Only disconnected sessions can be reset.";
|
||||||
|
statusClass = "warning";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
statusMessage = "Session not found or does not belong to you.";
|
||||||
|
statusClass = "error";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Redirect to clean URL after action
|
||||||
|
Response.Redirect(Request.Path + "?done=" + Server.UrlEncode(statusMessage) +
|
||||||
|
"&class=" + statusClass);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for post-redirect message
|
||||||
|
if (!string.IsNullOrEmpty(Request.QueryString["done"]))
|
||||||
|
{
|
||||||
|
statusMessage = Request.QueryString["done"];
|
||||||
|
statusClass = Request.QueryString["class"] ?? "success";
|
||||||
|
}
|
||||||
|
|
||||||
|
userSessions = GetSessions().FindAll(s =>
|
||||||
|
s.Username.Equals(currentUser, StringComparison.OrdinalIgnoreCase));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<SessionInfo> GetSessions()
|
||||||
|
{
|
||||||
|
var sessions = new List<SessionInfo>();
|
||||||
|
string output = RunCommand("query session");
|
||||||
|
if (string.IsNullOrEmpty(output)) return sessions;
|
||||||
|
|
||||||
|
foreach (string line in output.Split('\n'))
|
||||||
|
{
|
||||||
|
string trimmed = line.Trim();
|
||||||
|
if (string.IsNullOrEmpty(trimmed) || trimmed.StartsWith("SESSIONNAME"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Parse the fixed-width output from query session
|
||||||
|
// Format varies — use positional parsing
|
||||||
|
var match = Regex.Match(trimmed,
|
||||||
|
@"^[> ]*([\w-#]*)\s{2,}(\w+)\s+(\d+)\s+(\w+)");
|
||||||
|
if (match.Success)
|
||||||
|
{
|
||||||
|
sessions.Add(new SessionInfo
|
||||||
|
{
|
||||||
|
SessionName = match.Groups[1].Value.Trim(),
|
||||||
|
Username = match.Groups[2].Value.Trim(),
|
||||||
|
Id = int.Parse(match.Groups[3].Value),
|
||||||
|
State = match.Groups[4].Value.Trim(),
|
||||||
|
CanReset = match.Groups[4].Value.Trim() == "Disc"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Try alternate format (no session name, just username)
|
||||||
|
match = Regex.Match(trimmed, @"^\s+(\w+)\s+(\d+)\s+(\w+)");
|
||||||
|
if (match.Success)
|
||||||
|
{
|
||||||
|
sessions.Add(new SessionInfo
|
||||||
|
{
|
||||||
|
SessionName = "",
|
||||||
|
Username = match.Groups[1].Value.Trim(),
|
||||||
|
Id = int.Parse(match.Groups[2].Value),
|
||||||
|
State = match.Groups[3].Value.Trim(),
|
||||||
|
CanReset = match.Groups[3].Value.Trim() == "Disc"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sessions;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string RunCommand(string cmd)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var psi = new ProcessStartInfo("cmd.exe", "/c " + cmd)
|
||||||
|
{
|
||||||
|
RedirectStandardOutput = true,
|
||||||
|
RedirectStandardError = true,
|
||||||
|
UseShellExecute = false,
|
||||||
|
CreateNoWindow = true
|
||||||
|
};
|
||||||
|
var proc = Process.Start(psi);
|
||||||
|
string output = proc.StandardOutput.ReadToEnd();
|
||||||
|
proc.WaitForExit(10000);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
catch { return ""; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LogAction(string user, int sessionId, string action)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string logPath = Server.MapPath("~/logs");
|
||||||
|
if (!System.IO.Directory.Exists(logPath))
|
||||||
|
System.IO.Directory.CreateDirectory(logPath);
|
||||||
|
string logFile = System.IO.Path.Combine(logPath,
|
||||||
|
DateTime.Now.ToString("yyyy-MM") + ".log");
|
||||||
|
System.IO.File.AppendAllText(logFile,
|
||||||
|
string.Format("{0} | {1} | session {2} | {3}\r\n",
|
||||||
|
DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
|
||||||
|
user, sessionId, action));
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>Session Manager — SAGE-SQL</title>
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--bg: #0f1923;
|
||||||
|
--surface: #172a3a;
|
||||||
|
--surface2: #1e3448;
|
||||||
|
--border: #2a4a5e;
|
||||||
|
--text: #e0e8f0;
|
||||||
|
--text-muted: #7a9ab5;
|
||||||
|
--accent: #38bdf8;
|
||||||
|
--accent-hover: #7dd3fc;
|
||||||
|
--success: #22c55e;
|
||||||
|
--warning: #f59e0b;
|
||||||
|
--danger: #ef4444;
|
||||||
|
--disc: #f59e0b;
|
||||||
|
}
|
||||||
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||||
|
body {
|
||||||
|
font-family: 'Segoe UI', -apple-system, sans-serif;
|
||||||
|
background: var(--bg);
|
||||||
|
color: var(--text);
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 40px 20px;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
max-width: 720px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
margin-bottom: 32px;
|
||||||
|
}
|
||||||
|
.header-icon {
|
||||||
|
width: 48px; height: 48px;
|
||||||
|
background: var(--accent);
|
||||||
|
border-radius: 12px;
|
||||||
|
display: flex; align-items: center; justify-content: center;
|
||||||
|
font-size: 24px; font-weight: 700; color: var(--bg);
|
||||||
|
}
|
||||||
|
.header h1 {
|
||||||
|
font-size: 22px; font-weight: 600;
|
||||||
|
color: var(--text);
|
||||||
|
}
|
||||||
|
.header p {
|
||||||
|
font-size: 14px; color: var(--text-muted);
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
.welcome {
|
||||||
|
background: var(--surface);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 16px 20px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
display: flex; align-items: center; justify-content: space-between;
|
||||||
|
}
|
||||||
|
.welcome-user {
|
||||||
|
font-size: 15px; color: var(--text);
|
||||||
|
}
|
||||||
|
.welcome-user strong { color: var(--accent); }
|
||||||
|
.refresh-btn {
|
||||||
|
background: var(--surface2);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
color: var(--text-muted);
|
||||||
|
padding: 8px 16px;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 13px;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: all 0.15s;
|
||||||
|
}
|
||||||
|
.refresh-btn:hover {
|
||||||
|
background: var(--border);
|
||||||
|
color: var(--text);
|
||||||
|
}
|
||||||
|
.alert {
|
||||||
|
padding: 12px 16px;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
font-size: 14px;
|
||||||
|
border: 1px solid;
|
||||||
|
}
|
||||||
|
.alert.success { background: rgba(34,197,94,0.1); border-color: var(--success); color: var(--success); }
|
||||||
|
.alert.warning { background: rgba(245,158,11,0.1); border-color: var(--warning); color: var(--warning); }
|
||||||
|
.alert.error { background: rgba(239,68,68,0.1); border-color: var(--danger); color: var(--danger); }
|
||||||
|
.sessions-table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
background: var(--surface);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.sessions-table th {
|
||||||
|
text-align: left;
|
||||||
|
padding: 12px 16px;
|
||||||
|
font-size: 12px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
color: var(--text-muted);
|
||||||
|
background: var(--surface2);
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
.sessions-table td {
|
||||||
|
padding: 14px 16px;
|
||||||
|
font-size: 14px;
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
.sessions-table tr:last-child td { border-bottom: none; }
|
||||||
|
.state-badge {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 3px 10px;
|
||||||
|
border-radius: 20px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.3px;
|
||||||
|
}
|
||||||
|
.state-active { background: rgba(34,197,94,0.15); color: var(--success); }
|
||||||
|
.state-disc { background: rgba(245,158,11,0.15); color: var(--disc); }
|
||||||
|
.reset-btn {
|
||||||
|
background: var(--danger);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 6px 14px;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: opacity 0.15s;
|
||||||
|
}
|
||||||
|
.reset-btn:hover { opacity: 0.85; }
|
||||||
|
.no-sessions {
|
||||||
|
text-align: center;
|
||||||
|
padding: 48px 20px;
|
||||||
|
background: var(--surface);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
.no-sessions p { color: var(--text-muted); font-size: 15px; }
|
||||||
|
.no-sessions .check { font-size: 40px; margin-bottom: 12px; color: var(--success); }
|
||||||
|
.footer {
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 32px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--text-muted);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="header">
|
||||||
|
<div class="header-icon">S</div>
|
||||||
|
<div>
|
||||||
|
<h1>Session Manager</h1>
|
||||||
|
<p>SAGE-SQL — Reset disconnected RemoteApp sessions</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="welcome">
|
||||||
|
<span class="welcome-user">Signed in as <strong><%= currentDisplayName %></strong></span>
|
||||||
|
<a href="<%= Request.Path %>" class="refresh-btn">Refresh</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<% if (!string.IsNullOrEmpty(statusMessage)) { %>
|
||||||
|
<div class="alert <%= statusClass %>"><%= Server.HtmlEncode(statusMessage) %></div>
|
||||||
|
<% } %>
|
||||||
|
|
||||||
|
<% if (userSessions.Count > 0) { %>
|
||||||
|
<table class="sessions-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Session</th>
|
||||||
|
<th>State</th>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Action</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<% foreach (var s in userSessions) { %>
|
||||||
|
<tr>
|
||||||
|
<td><%= string.IsNullOrEmpty(s.SessionName) ? "RemoteApp" : Server.HtmlEncode(s.SessionName) %></td>
|
||||||
|
<td>
|
||||||
|
<span class="state-badge <%= s.State == "Disc" ? "state-disc" : "state-active" %>">
|
||||||
|
<%= s.State == "Disc" ? "Disconnected" : s.State %>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>#<%= s.Id %></td>
|
||||||
|
<td>
|
||||||
|
<% if (s.CanReset) { %>
|
||||||
|
<a href="?reset=<%= s.Id %>" class="reset-btn"
|
||||||
|
onclick="return confirm('Reset session #<%= s.Id %>?')">Reset</a>
|
||||||
|
<% } else { %>
|
||||||
|
<span style="color: var(--text-muted); font-size: 13px;">Active</span>
|
||||||
|
<% } %>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<% } %>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<% } else { %>
|
||||||
|
<div class="no-sessions">
|
||||||
|
<div class="check">✓</div>
|
||||||
|
<p>No sessions found for your account.<br>You're all clear.</p>
|
||||||
|
</div>
|
||||||
|
<% } %>
|
||||||
|
|
||||||
|
<div class="footer">
|
||||||
|
Dataforth Corporation — IT Services by AZ Computer Guru
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
18
clients/dataforth/session-manager/web.config
Normal file
18
clients/dataforth/session-manager/web.config
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<configuration>
|
||||||
|
<system.web>
|
||||||
|
<authentication mode="Windows" />
|
||||||
|
<authorization>
|
||||||
|
<deny users="?" />
|
||||||
|
</authorization>
|
||||||
|
<compilation targetFramework="4.0" />
|
||||||
|
</system.web>
|
||||||
|
<system.webServer>
|
||||||
|
<security>
|
||||||
|
<authentication>
|
||||||
|
<windowsAuthentication enabled="true" />
|
||||||
|
<anonymousAuthentication enabled="false" />
|
||||||
|
</authentication>
|
||||||
|
</security>
|
||||||
|
</system.webServer>
|
||||||
|
</configuration>
|
||||||
@@ -215,3 +215,49 @@ Built `/syncro` slash command for ticket management via Syncro REST API.
|
|||||||
- Ollama URL: `http://100.92.127.64:11434`
|
- Ollama URL: `http://100.92.127.64:11434`
|
||||||
- Firewall: inbound TCP 11434 from 100.0.0.0/8 only
|
- Firewall: inbound TCP 11434 from 100.0.0.0/8 only
|
||||||
- Env var: `OLLAMA_HOST=0.0.0.0:11434` (User scope on DESKTOP-0O8A1RL)
|
- Env var: `OLLAMA_HOST=0.0.0.0:11434` (User scope on DESKTOP-0O8A1RL)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Update: 20:00 — SAGE-SQL session manager, shared work items
|
||||||
|
|
||||||
|
### Dataforth SAGE-SQL session manager — built, not yet deployed
|
||||||
|
Built self-service session reset web app for Dataforth users on SAGE-SQL (192.168.0.153, Windows Server 2016).
|
||||||
|
|
||||||
|
**Problem:** Users connect via RemoteApps to SAGE. Sessions hang/disconnect and require IT to remote in and logoff sessions manually.
|
||||||
|
|
||||||
|
**Solution:** Single-file ASP.NET WebForms app (`Default.aspx` + `web.config`) that:
|
||||||
|
- Uses Windows Authentication (auto-identifies domain user, no login needed)
|
||||||
|
- Shows only the authenticated user's own RDP/RemoteApp sessions
|
||||||
|
- Only allows resetting disconnected ("Disc") sessions, not active ones
|
||||||
|
- Confirmation prompt before reset
|
||||||
|
- Logs all reset actions to monthly log files at `~/logs/YYYY-MM.log`
|
||||||
|
- Dark themed UI
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- `clients/dataforth/session-manager/Default.aspx` — full app (server-side C# + HTML/CSS)
|
||||||
|
- `clients/dataforth/session-manager/web.config` — IIS config (Windows Auth on, Anonymous off)
|
||||||
|
|
||||||
|
**Deployment blocked:** VPN connectivity issues — SSH to AD2 times out (ICMP works, TCP blocked), WinRM to SAGE-SQL blocked, RMM API at 172.16.3.30:3001 unreachable. Deferred to next session.
|
||||||
|
|
||||||
|
**Deployment steps (for tomorrow):**
|
||||||
|
1. Create `C:\inetpub\sessions\` on SAGE-SQL
|
||||||
|
2. Copy Default.aspx + web.config to that directory
|
||||||
|
3. Create IIS application: `New-WebApplication -Name "sessions" -Site "Default Web Site" -PhysicalPath "C:\inetpub\sessions" -ApplicationPool "DefaultAppPool"`
|
||||||
|
4. Verify Windows Auth enabled, Anonymous Auth disabled
|
||||||
|
5. Test at `http://sage-sql/sessions/`
|
||||||
|
6. App pool identity (NetworkService) should have permission to run `logoff` command
|
||||||
|
|
||||||
|
**WinRM TrustedHosts updated:** Added `192.168.0.153,SAGE-SQL` to local TrustedHosts for future NTLM auth (workstation not domain-joined).
|
||||||
|
|
||||||
|
### Shared work items board — created
|
||||||
|
Created `WORKITEMS.md` at repo root — shared task list that syncs via Gitea.
|
||||||
|
- Both Mike and Howard can add/claim/complete items
|
||||||
|
- Uses `@mike`/`@howard`/`@unassigned` tagging
|
||||||
|
- Populated with all carry-over items from this session and previous days
|
||||||
|
- Claude can read/update it on request ("show work items", "add work item: ...")
|
||||||
|
|
||||||
|
### Network issues (end of day)
|
||||||
|
- AD2 (192.168.0.6): ICMP ping works (23-46ms), SSH port 22 times out
|
||||||
|
- SAGE-SQL (192.168.0.153): WinRM port 5985 unreachable from workstation
|
||||||
|
- RMM server (172.16.3.30:3001): connection times out
|
||||||
|
- Likely VPN/firewall filtering TCP but passing ICMP
|
||||||
|
|||||||
Reference in New Issue
Block a user