Skip to content

Commit 562ffcb

Browse files
feat(windows): GUI for the context-menu manager + bulletproof send-to logging
- windows-context-menu-manager: now opens a WinForms window (tick/untick each entry, live filter, refresh, restart Explorer) instead of a text list; -Console keeps the text mode. .cmd elevates and hides its console. - send-to diagnosis: launch.vbs now writes launch.log when it fires, and send.ps1 logs every step via .NET (config load, token decrypt, MKCOL and each PUT with curl exit code) under a trap, so a failed/silent upload leaves a trace instead of vanishing with the hidden window.
1 parent bf430d6 commit 562ffcb

4 files changed

Lines changed: 246 additions & 85 deletions

File tree

scripts/send-to/windows/launch.vbs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,33 @@
22
'
33
' Invoked by the "Send to", "Drop on OpenCoperLock" and "Multi-Drop on OpenCoperLock" entries with
44
' the selected file path(s) as arguments. It forwards them to send.ps1 and runs PowerShell HIDDEN
5-
' (window style 0) so no console flashes. VBScript via wscript.exe is the reliable way to receive
6-
' the selected files AND stay windowless.
5+
' (window style 0) so no console flashes. It also writes launch.log so we can tell whether the menu
6+
' entry actually fired (if launch.log grows but send.log does not, PowerShell/send.ps1 is the issue).
77
Option Explicit
8-
Dim sh, dst, cmd, i
8+
Dim sh, fso, dst, cmd, i, logPath, log
99
Set sh = CreateObject("WScript.Shell")
10+
Set fso = CreateObject("Scripting.FileSystemObject")
1011
dst = sh.ExpandEnvironmentStrings("%LOCALAPPDATA%") & "\OpenCoperLock"
1112

13+
logPath = dst & "\launch.log"
14+
On Error Resume Next
15+
Set log = fso.OpenTextFile(logPath, 8, True) ' 8 = append, True = create if missing
16+
log.WriteLine Now & " launch.vbs fired, args=" & WScript.Arguments.Count
17+
On Error GoTo 0
18+
1219
cmd = "powershell.exe -NoProfile -ExecutionPolicy Bypass -File """ & dst & "\send.ps1"""
1320
For i = 0 To WScript.Arguments.Count - 1
1421
cmd = cmd & " """ & WScript.Arguments(i) & """"
22+
On Error Resume Next
23+
If Not (log Is Nothing) Then log.WriteLine " arg: " & WScript.Arguments(i)
24+
On Error GoTo 0
1525
Next
1626

17-
' 0 = hidden window, False = don't wait (return immediately so Explorer isn't blocked).
27+
On Error Resume Next
28+
If Not (log Is Nothing) Then
29+
log.WriteLine " run: " & cmd
30+
log.Close
31+
End If
32+
On Error GoTo 0
33+
1834
sh.Run cmd, 0, False

scripts/send-to/windows/send.ps1

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,25 @@
33
44
Invoked (via launch.vbs, hidden) with one or more file paths as arguments. Uploads each selected
55
file to the "ComputerShared" space (a top-level folder in your Drive) over WebDAV, shows a small
6-
tray notification, and appends a line to send.log so problems can be diagnosed. Configuration
6+
tray notification, and writes a detailed send.log so any problem can be diagnosed. Configuration
77
(WebDAV URL + DPAPI-encrypted token + options) lives in %LOCALAPPDATA%\OpenCoperLock\config.json.
88
#>
9-
$ErrorActionPreference = 'Stop'
109
$dir = Join-Path $env:LOCALAPPDATA 'OpenCoperLock'
1110
$cfgPath = Join-Path $dir 'config.json'
1211
$icon = Join-Path $dir 'opencoperlock.ico'
1312
$logPath = Join-Path $dir 'send.log'
1413

14+
# Bulletproof logging via .NET so we always get a trace, even if something fails very early.
1515
function Log($msg) {
16-
try { Add-Content -LiteralPath $logPath -Value ("{0} {1}" -f (Get-Date -Format 'yyyy-MM-dd HH:mm:ss'), $msg) } catch { }
16+
try {
17+
if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Force -Path $dir | Out-Null }
18+
[System.IO.File]::AppendAllText($logPath, ("{0} {1}`r`n" -f (Get-Date -Format 'yyyy-MM-dd HH:mm:ss'), $msg))
19+
} catch { }
1720
}
21+
# Any uncaught error is logged instead of vanishing with the hidden window.
22+
trap { Log "FATAL: $($_.Exception.Message)"; exit 1 }
23+
24+
Log "=== send.ps1 start; args=$($args.Count): $($args -join ' | ')"
1825

1926
function Show-Toast($title, $text) {
2027
if ($script:notify -eq $false) { return }
@@ -30,36 +37,44 @@ function Show-Toast($title, $text) {
3037
} catch { Log "toast failed: $($_.Exception.Message)" }
3138
}
3239

33-
Log "invoked with $($args.Count) arg(s): $($args -join ' | ')"
40+
if (-not (Test-Path $cfgPath)) { Log 'no config.json - run the installer'; Show-Toast 'OpenCoperLock' 'Not configured yet - run the installer.'; exit 1 }
3441

35-
if (-not (Test-Path $cfgPath)) { Log 'no config'; Show-Toast 'OpenCoperLock' 'Not configured yet - run the installer.'; exit 1 }
36-
37-
$cfg = Get-Content $cfgPath -Raw | ConvertFrom-Json
42+
$cfg = Get-Content $cfgPath -Raw | ConvertFrom-Json
3843
$base = ($cfg.base).TrimEnd('/')
3944
$script:notify = -not ($cfg.PSObject.Properties.Name -contains 'notify' -and $cfg.notify -eq $false)
45+
Log "config loaded; base=$base notify=$script:notify"
4046

4147
# Decrypt the DPAPI-protected token.
42-
$sec = ConvertTo-SecureString $cfg.token
43-
$bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($sec)
44-
$tok = [Runtime.InteropServices.Marshal]::PtrToStringAuto($bstr)
45-
[Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr)
48+
try {
49+
$sec = ConvertTo-SecureString $cfg.token # DPAPI, current user
50+
$bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($sec)
51+
$tok = [Runtime.InteropServices.Marshal]::PtrToStringAuto($bstr)
52+
[Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr)
53+
} catch { Log "token decrypt failed: $($_.Exception.Message)"; Show-Toast 'OpenCoperLock' 'Token unreadable - re-run the installer.'; exit 1 }
54+
Log "token decrypted; length=$($tok.Length)"
55+
56+
$curl = "$env:SystemRoot\System32\curl.exe"
57+
if (-not (Test-Path $curl)) { $curl = 'curl.exe' } # fall back to PATH
4658

4759
$files = @($args | Where-Object { $_ -and (Test-Path -LiteralPath $_ -PathType Leaf) })
48-
if ($files.Count -eq 0) { Log 'no files after filter'; Show-Toast 'OpenCoperLock' 'No files to send (folders are skipped).'; exit 0 }
60+
Log "files to send: $($files.Count)"
61+
if ($files.Count -eq 0) { Show-Toast 'OpenCoperLock' 'No files to send (folders are skipped).'; exit 0 }
4962

5063
$cred = "me:$tok"
5164
# Make sure the space exists (a 405 "already there" is fine and ignored).
52-
& curl.exe -s -u $cred -X MKCOL "$base/ComputerShared/" | Out-Null
65+
$mk = & $curl -s -o NUL -w "%{http_code}" -u $cred -X MKCOL "$base/ComputerShared/" 2>&1
66+
Log "MKCOL ComputerShared -> $mk (curl exit $LASTEXITCODE)"
5367

5468
$ok = 0; $fail = 0
5569
foreach ($f in $files) {
56-
$name = [uri]::EscapeDataString((Split-Path -LiteralPath $f -Leaf))
57-
$code = & curl.exe -s -o NUL -w "%{http_code}" -u $cred -T $f "$base/ComputerShared/$name"
58-
Log "PUT $f -> $base/ComputerShared/$name = $code"
59-
if ($code -match '^2') { $ok++ } else { $fail++ }
70+
$leaf = Split-Path -LiteralPath $f -Leaf
71+
$name = [uri]::EscapeDataString($leaf)
72+
$code = & $curl -s -o NUL -w "%{http_code}" -u $cred -T $f "$base/ComputerShared/$name" 2>&1
73+
Log "PUT '$leaf' -> $base/ComputerShared/$name = $code (curl exit $LASTEXITCODE)"
74+
if ("$code" -match '^2\d\d') { $ok++ } else { $fail++ }
6075
}
6176
$tok = $null; $cred = $null
6277

63-
Log "done: ok=$ok fail=$fail"
78+
Log "=== done: ok=$ok fail=$fail"
6479
if ($fail -eq 0) { Show-Toast 'OpenCoperLock' "Sent $ok file(s) to ComputerShared." }
6580
else { Show-Toast 'OpenCoperLock' "Sent $ok, $fail failed - see send.log." }
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
@echo off
22
REM ===========================================================================
3-
REM OpenCoperLock - Windows right-click menu manager (elevated).
4-
REM Double-click to tidy the Explorer right-click menu. Requests Administrator
5-
REM so it can also manage system-wide entries. Nothing is deleted - items are
6-
REM just disabled/enabled reversibly.
3+
REM OpenCoperLock - Windows right-click menu manager (GUI, elevated).
4+
REM Double-click to open a small window that lists every right-click entry and
5+
REM lets you tick/untick each one. Requests Administrator so it can manage
6+
REM system-wide entries too. Nothing is deleted - toggles are reversible.
77
REM ===========================================================================
88
powershell -NoProfile -ExecutionPolicy Bypass -Command ^
9-
"Start-Process powershell -Verb RunAs -ArgumentList '-NoProfile','-ExecutionPolicy','Bypass','-NoExit','-File','\"%~dp0windows-context-menu-manager.ps1\"'"
9+
"Start-Process powershell -Verb RunAs -ArgumentList '-NoProfile','-ExecutionPolicy','Bypass','-WindowStyle','Hidden','-File','\"%~dp0windows-context-menu-manager.ps1\"'"

0 commit comments

Comments
 (0)