[Console]::OutputEncoding = [Text.Encoding]::UTF8 $ErrorActionPreference = 'Stop' $configPath = Join-Path $PSScriptRoot 'nirsoft-config.json' $cfg = Get-Content $configPath -Raw -Encoding UTF8 | ConvertFrom-Json $installRoot = $cfg.InstallRoot $shortcutRoot = $cfg.ShortcutRoot New-Item -ItemType Directory -Force -Path $installRoot | Out-Null New-Item -ItemType Directory -Force -Path $shortcutRoot | Out-Null [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $wsh = New-Object -ComObject WScript.Shell function Install-OneTool { param($tool) $toolDir = Join-Path $installRoot $tool.Name $exePath = Join-Path $toolDir $tool.Exe if (Test-Path $exePath) { $ver = (Get-Item $exePath).VersionInfo.ProductVersion Write-Host "[=] $($tool.Name) already installed (v$ver)" } else { Write-Host "[*] $($tool.Name) downloading $($tool.Url)" $tmpZip = Join-Path $env:TEMP "$($tool.Name).zip" $tmpDir = Join-Path $env:TEMP "$($tool.Name)-extract" if (Test-Path $tmpDir) { Remove-Item $tmpDir -Recurse -Force } New-Item -ItemType Directory -Path $tmpDir | Out-Null try { Invoke-WebRequest -Uri $tool.Url -OutFile $tmpZip -UseBasicParsing if ((Get-Item $tmpZip).Length -lt 20KB) { throw "download too small" } Expand-Archive -Path $tmpZip -DestinationPath $tmpDir -Force if (-not (Test-Path (Join-Path $tmpDir $tool.Exe))) { # Some NirSoft archives nest the exe; search $found = Get-ChildItem $tmpDir -Recurse -Filter $tool.Exe -ErrorAction SilentlyContinue | Select-Object -First 1 if (-not $found) { throw "$($tool.Exe) not found in archive" } Copy-Item -Path (Split-Path $found.FullName) -Destination $toolDir -Recurse -Force } else { New-Item -ItemType Directory -Force -Path $toolDir | Out-Null Copy-Item -Path (Join-Path $tmpDir '*') -Destination $toolDir -Recurse -Force } $ver = (Get-Item $exePath).VersionInfo.ProductVersion Write-Host "[OK] $($tool.Name) v$ver -> $toolDir" } finally { Remove-Item $tmpZip -Force -ErrorAction SilentlyContinue Remove-Item $tmpDir -Recurse -Force -ErrorAction SilentlyContinue } } # Admin-only Start Menu shortcut under NirSoft\ $lnk = $wsh.CreateShortcut((Join-Path $shortcutRoot "$($tool.Name).lnk")) $lnk.TargetPath = $exePath $lnk.WorkingDirectory = $toolDir $lnk.IconLocation = "$exePath,0" $lnk.Save() } # --- Install all tools --- foreach ($t in $cfg.Tools) { try { Install-OneTool -tool $t } catch { Write-Host "[!] $($t.Name) failed: $($_.Exception.Message)" } } # --- Reorganize existing CurrPorts shortcuts (hide from User) --- Write-Host "" Write-Host "[*] Reorganizing CurrPorts shortcuts (hide from User)" $cpExe = Join-Path $installRoot 'CurrPorts\cports.exe' if (Test-Path $cpExe) { # Create in Admin's NirSoft folder $lnk = $wsh.CreateShortcut((Join-Path $shortcutRoot 'CurrPorts.lnk')) $lnk.TargetPath = $cpExe $lnk.WorkingDirectory = Split-Path $cpExe $lnk.IconLocation = "$cpExe,0" $lnk.Save() Write-Host " - added to Admin's NirSoft Start Menu" } # Remove visible CurrPorts shortcuts that the User would see $visibleShortcuts = @( 'C:\ProgramData\Microsoft\Windows\Start Menu\Programs\CurrPorts.lnk', 'C:\Users\user\Desktop\CurrPorts.lnk', 'C:\Users\User\Desktop\CurrPorts.lnk' ) foreach ($s in $visibleShortcuts) { if (Test-Path $s) { Remove-Item $s -Force -ErrorAction SilentlyContinue Write-Host " - removed $s" } } Write-Host "" Write-Host "===== Summary =====" Write-Host "Installed to: $installRoot" Write-Host "Shortcuts: $shortcutRoot (Admin's Start Menu only, not visible to 'User')" Write-Host "" Write-Host "All tools support CSV/text output via /scomma /stext /shtml /sxml flags, e.g.:" Write-Host " cports.exe /scomma ports.csv" Write-Host " InstalledAppsView.exe /scomma apps.csv" Write-Host " LastActivityView.exe /scomma activity.csv"