Initial commit

This commit is contained in:
2026-04-24 17:41:53 +08:00
commit 7105e8b165
94 changed files with 8141 additions and 0 deletions

View File

@@ -0,0 +1,133 @@
[Console]::OutputEncoding = [Text.Encoding]::UTF8
$ErrorActionPreference = 'Continue'
Write-Host "[*] Windows 啟用腳本"
Write-Host ""
# 檢查管理員權限
if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Write-Host "[!] 需要管理員權限才能執行此腳本" -ForegroundColor Red
exit 1
}
# 檢查目前啟用狀態
Write-Host "[*] 檢查目前啟用狀態"
$license = Get-CimInstance -ClassName SoftwareLicensingProduct | Where-Object {$_.PartialProductKey}
$currentStatus = $license | Select-Object Name, LicenseStatus, Description, GracePeriodRemaining
Write-Host "目前狀態:$($currentStatus.Name)"
Write-Host "授權狀態:$($currentStatus.LicenseStatus) ($($currentStatus.Description))"
Write-Host "剩餘期間:$($currentStatus.GracePeriodRemaining) 分鐘"
Write-Host ""
if ($currentStatus.LicenseStatus -eq 1) {
Write-Host "[OK] Windows 已經啟用,無需執行啟用程序" -ForegroundColor Green
exit 0
}
# 偵測 Windows 版本並設定對應的 GVLK
Write-Host "[*] 偵測 Windows 版本"
$osInfo = Get-ComputerInfo
$windowsEdition = $osInfo.WindowsProductName
Write-Host "Windows 版本:$windowsEdition"
# 常見 Windows 版本的 GVLK (Generic Volume License Keys)
$gvlkKeys = @{
'Windows 10 Pro' = 'W269N-WFGWX-YVC9B-4J6C9-T83GX'
'Windows 10 Professional' = 'W269N-WFGWX-YVC9B-4J6C9-T83GX'
'Windows 10 Home' = 'TX9XD-98N7V-6WMQ6-BX7FG-H8Q99'
'Windows 10 Enterprise' = 'NPPR9-FWDCX-D2C8J-H872K-2YT43'
'Windows 11 Pro' = 'W269N-WFGWX-YVC9B-4J6C9-T83GX'
'Windows 11 Professional' = 'W269N-WFGWX-YVC9B-4J6C9-T83GX'
'Windows 11 Home' = 'TX9XD-98N7V-6WMQ6-BX7FG-H8Q99'
'Windows 11 Enterprise' = 'NPPR9-FWDCX-D2C8J-H872K-2YT43'
}
$productKey = $null
foreach ($edition in $gvlkKeys.Keys) {
if ($windowsEdition -like "*$edition*") {
$productKey = $gvlkKeys[$edition]
break
}
}
if (-not $productKey) {
# 預設使用 Pro 版本的金鑰
$productKey = 'W269N-WFGWX-YVC9B-4J6C9-T83GX'
Write-Host "[*] 無法偵測到確切版本,使用 Pro 版本金鑰" -ForegroundColor Yellow
}
Write-Host "使用產品金鑰:$productKey"
Write-Host ""
# KMS 伺服器清單
$kmsServers = @(
'kms.digiboy.ir',
'kms8.msguides.com',
'kms.03k.org',
'kms.chinancce.com'
)
Write-Host "[*] 開始啟用程序"
# 1. 安裝產品金鑰
Write-Host "[1/3] 安裝產品金鑰"
try {
& slmgr /ipk $productKey
Start-Sleep -Seconds 3
Write-Host " 產品金鑰安裝成功"
} catch {
Write-Host " [!] 產品金鑰安裝失敗: $($_.Exception.Message)" -ForegroundColor Red
}
# 2. 嘗試 KMS 伺服器
Write-Host "[2/3] 設定 KMS 伺服器並啟用"
$activated = $false
foreach ($kmsServer in $kmsServers) {
Write-Host " 嘗試 KMS 伺服器:$kmsServer"
try {
# 設定 KMS 伺服器
& slmgr /skms $kmsServer
Start-Sleep -Seconds 2
# 執行啟用
& slmgr /ato
Start-Sleep -Seconds 5
# 檢查啟用結果
$newStatus = Get-CimInstance -ClassName SoftwareLicensingProduct | Where-Object {$_.PartialProductKey}
if ($newStatus.LicenseStatus -eq 1) {
$activated = $true
Write-Host " [OK] 啟用成功!" -ForegroundColor Green
break
} else {
Write-Host " 啟用未成功,嘗試下一個伺服器"
}
} catch {
Write-Host " KMS 伺服器連線失敗: $($_.Exception.Message)" -ForegroundColor Yellow
}
}
# 3. 驗證啟用結果
Write-Host "[3/3] 驗證啟用結果"
$finalStatus = Get-CimInstance -ClassName SoftwareLicensingProduct | Where-Object {$_.PartialProductKey}
Write-Host ""
Write-Host "=== 啟用結果 ==="
Write-Host "版本:$($finalStatus.Name)"
Write-Host "狀態:$($finalStatus.LicenseStatus) ($($finalStatus.Description))"
Write-Host "剩餘期間:$($finalStatus.GracePeriodRemaining) 分鐘 (約 $([math]::Round($finalStatus.GracePeriodRemaining / 1440, 1)) 天)"
if ($finalStatus.LicenseStatus -eq 1) {
Write-Host ""
Write-Host "[OK] Windows 啟用成功!" -ForegroundColor Green
Write-Host "KMS 啟用有效期約 180 天,會自動續期。"
exit 0
} else {
Write-Host ""
Write-Host "[!] Windows 啟用失敗" -ForegroundColor Red
Write-Host "請檢查網路連線或嘗試其他啟用方法。"
exit 1
}

View File

@@ -0,0 +1,127 @@
[Console]::OutputEncoding = [Text.Encoding]::UTF8
$ErrorActionPreference = 'Continue'
param(
[string]$TargetUser = 'User'
)
Write-Host "[*] Adding desktop icons for user: $TargetUser"
# Icon GUIDs
$computerGUID = "{20D04FE0-3AEA-1069-A2D8-08002B30309D}" # This PC / Computer
$controlPanelGUID = "{5399E694-6CE5-4D6C-8FCE-1D8870FDCBA0}" # Control Panel
$recycleGUID = "{645FF040-5081-101B-9F08-00AA002F954E}" # Recycle Bin
# Check if user exists
$userProfile = "C:\Users\$TargetUser"
if (-not (Test-Path $userProfile)) {
Write-Host "[!] User profile not found: $userProfile" -ForegroundColor Red
exit 1
}
Write-Host "[*] Target user profile: $userProfile"
# Check if user is currently logged in (hive already loaded)
$hivePath = "HKU:\${TargetUser}_Classes"
$userSID = $null
try {
# Get user SID
$user = New-Object System.Security.Principal.NTAccount($TargetUser)
$userSID = $user.Translate([System.Security.Principal.SecurityIdentifier]).Value
Write-Host "[*] User SID: $userSID"
} catch {
Write-Host "[!] Could not get user SID: $($_.Exception.Message)" -ForegroundColor Red
exit 1
}
# Check if user hive is already loaded
$hiveLoaded = $false
$userHivePath = "HKU:\$userSID"
if (Test-Path $userHivePath) {
Write-Host "[*] User hive already loaded"
$hiveLoaded = $true
} else {
Write-Host "[*] Loading user hive"
$ntUserPath = "$userProfile\NTUSER.DAT"
if (-not (Test-Path $ntUserPath)) {
Write-Host "[!] NTUSER.DAT not found: $ntUserPath" -ForegroundColor Red
exit 1
}
try {
& reg load "HKU\$TargetUser" "$ntUserPath"
if ($LASTEXITCODE -eq 0) {
Write-Host " User hive loaded successfully"
$userHivePath = "HKU:\$TargetUser"
} else {
Write-Host "[!] Failed to load user hive" -ForegroundColor Red
exit 1
}
} catch {
Write-Host "[!] Error loading user hive: $($_.Exception.Message)" -ForegroundColor Red
exit 1
}
}
# Desktop icons registry paths
$desktopIconsPath = "$userHivePath\Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\NewStartPanel"
$classicIconsPath = "$userHivePath\Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\ClassicStartMenu"
Write-Host "[*] Setting up desktop icons"
# Ensure registry paths exist
foreach ($path in @($desktopIconsPath, $classicIconsPath)) {
if (-not (Test-Path $path)) {
New-Item -Path $path -Force | Out-Null
Write-Host " Created registry path: $path"
}
}
# Enable icons (0 = show, 1 = hide)
$iconsToEnable = @{
"Computer (This PC)" = $computerGUID
"Control Panel" = $controlPanelGUID
"Recycle Bin" = $recycleGUID
}
foreach ($iconName in $iconsToEnable.Keys) {
$guid = $iconsToEnable[$iconName]
# Set for both NewStartPanel and ClassicStartMenu
Set-ItemProperty -Path $desktopIconsPath -Name $guid -Value 0 -Type DWord
Set-ItemProperty -Path $classicIconsPath -Name $guid -Value 0 -Type DWord
Write-Host " Enabled: $iconName"
}
# Unload user hive if we loaded it
if (-not $hiveLoaded) {
Write-Host "[*] Unloading user hive"
try {
& reg unload "HKU\$TargetUser"
if ($LASTEXITCODE -eq 0) {
Write-Host " User hive unloaded successfully"
} else {
Write-Host "[!] Warning: Failed to unload user hive cleanly"
}
} catch {
Write-Host "[!] Warning: Error unloading user hive: $($_.Exception.Message)"
}
}
Write-Host ""
Write-Host "[OK] Desktop icons configured for user: $TargetUser"
Write-Host ""
Write-Host "The following icons will appear on $TargetUser's desktop:"
Write-Host "- This PC (Computer)"
Write-Host "- Control Panel"
Write-Host "- Recycle Bin"
Write-Host ""
Write-Host "Changes will take effect when $TargetUser logs in next time."
Write-Host "If $TargetUser is currently logged in, they may need to:"
Write-Host "1. Log out and log back in"
Write-Host "2. Or restart the computer"
Write-Host "3. Or right-click desktop > Refresh"

View File

@@ -0,0 +1,100 @@
[Console]::OutputEncoding = [Text.Encoding]::UTF8
$ErrorActionPreference = 'Continue'
Write-Host "[*] Adding Computer and Control Panel icons to desktop"
# Registry paths for desktop icons
$desktopIconsPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\NewStartPanel"
$classicIconsPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\ClassicStartMenu"
# Icon GUIDs
$computerGUID = "{20D04FE0-3AEA-1069-A2D8-08002B30309D}" # This PC / Computer
$controlPanelGUID = "{5399E694-6CE5-4D6C-8FCE-1D8870FDCBA0}" # Control Panel
$recycleGUID = "{645FF040-5081-101B-9F08-00AA002F954E}" # Recycle Bin
$userFilesGUID = "{59031a47-3f72-44a7-89c5-5595fe6b30ee}" # User Files
$networkGUID = "{F02C1A0D-BE21-4350-88B0-7367FC96EF3C}" # Network
Write-Host "[*] Ensuring registry paths exist"
# Ensure registry paths exist
if (-not (Test-Path $desktopIconsPath)) {
New-Item -Path $desktopIconsPath -Force | Out-Null
Write-Host " Created registry path: NewStartPanel"
}
if (-not (Test-Path $classicIconsPath)) {
New-Item -Path $classicIconsPath -Force | Out-Null
Write-Host " Created registry path: ClassicStartMenu"
}
Write-Host "[*] Current desktop icon status"
# Check current status
$currentIcons = @{
"Computer" = $computerGUID
"Control Panel" = $controlPanelGUID
"Recycle Bin" = $recycleGUID
"User Files" = $userFilesGUID
"Network" = $networkGUID
}
foreach ($iconName in $currentIcons.Keys) {
$guid = $currentIcons[$iconName]
$value = Get-ItemProperty -Path $desktopIconsPath -Name $guid -ErrorAction SilentlyContinue
if ($value) {
$status = if ($value.$guid -eq 0) { "Visible" } else { "Hidden" }
} else {
$status = "Default (Hidden)"
}
Write-Host " $iconName : $status"
}
Write-Host "[*] Enabling Computer and Control Panel icons"
# Enable Computer icon (This PC)
Set-ItemProperty -Path $desktopIconsPath -Name $computerGUID -Value 0
Set-ItemProperty -Path $classicIconsPath -Name $computerGUID -Value 0
Write-Host " Computer (This PC) icon enabled"
# Enable Control Panel icon
Set-ItemProperty -Path $desktopIconsPath -Name $controlPanelGUID -Value 0
Set-ItemProperty -Path $classicIconsPath -Name $controlPanelGUID -Value 0
Write-Host " Control Panel icon enabled"
# Keep Recycle Bin enabled (it's probably already enabled)
Set-ItemProperty -Path $desktopIconsPath -Name $recycleGUID -Value 0
Set-ItemProperty -Path $classicIconsPath -Name $recycleGUID -Value 0
Write-Host " Recycle Bin icon ensured enabled"
Write-Host "[*] Refreshing desktop"
# Refresh the desktop to apply changes
try {
# Method 1: Use rundll32 to refresh
& rundll32.exe user32.dll,UpdatePerUserSystemParameters
# Method 2: Refresh explorer (more reliable)
$explorerProcesses = Get-Process explorer -ErrorAction SilentlyContinue
if ($explorerProcesses) {
Write-Host " Restarting Explorer to apply changes..."
Stop-Process -Name explorer -Force
Start-Sleep -Seconds 2
Start-Process explorer
Write-Host " Explorer restarted"
}
} catch {
Write-Host " [!] Could not restart Explorer: $($_.Exception.Message)"
Write-Host " Please restart Explorer manually or reboot to see changes"
}
Write-Host ""
Write-Host "[OK] Desktop icons setup complete!"
Write-Host ""
Write-Host "Enabled icons:"
Write-Host "- This PC (Computer)"
Write-Host "- Control Panel"
Write-Host "- Recycle Bin"
Write-Host ""
Write-Host "If icons don't appear immediately:"
Write-Host "1. Right-click desktop > Refresh"
Write-Host "2. Or restart the computer"

View File

@@ -0,0 +1,77 @@
param(
[string]$TargetUser = 'user'
)
[Console]::OutputEncoding = [Text.Encoding]::UTF8
$ErrorActionPreference = 'Stop'
# Resolve target user's SID
try {
$sid = (New-Object System.Security.Principal.NTAccount($TargetUser)).Translate([System.Security.Principal.SecurityIdentifier]).Value
} catch {
throw "Unable to resolve SID for user '$TargetUser': $_"
}
$ntuserDat = "C:\Users\$TargetUser\NTUSER.DAT"
$hivePath = "HKEY_USERS\$sid"
$regBase = "Registry::$hivePath"
$hiveLoaded = Test-Path $regBase
$weLoaded = $false
if (-not $hiveLoaded) {
if (-not (Test-Path $ntuserDat)) { throw "NTUSER.DAT not found: $ntuserDat" }
Write-Host "[*] User hive not loaded. Loading $ntuserDat as $hivePath"
& reg.exe load $hivePath $ntuserDat | Out-Null
if ($LASTEXITCODE -ne 0) { throw "reg load failed ($LASTEXITCODE). Is the user logged in?" }
$weLoaded = $true
} else {
Write-Host "[*] User hive already loaded at $hivePath (user may be logged in)"
}
function Set-UV {
param([string]$SubPath, [string]$Name, $Value, [string]$Type = 'DWord')
$full = "$regBase\$SubPath"
if (-not (Test-Path $full)) { New-Item -Path $full -Force | Out-Null }
New-ItemProperty -Path $full -Name $Name -Value $Value -PropertyType $Type -Force | Out-Null
Write-Host (" {0}\{1} = {2}" -f $SubPath, $Name, $Value)
}
try {
Write-Host "[*] Applying Explorer / Taskbar / Theme settings"
Set-UV 'Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced' 'HideFileExt' 0
Set-UV 'Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced' 'Hidden' 1
Set-UV 'Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced' 'TaskbarAl' 0
Set-UV 'Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced' 'ShowTaskViewButton' 0
Set-UV 'Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced' 'LaunchTo' 1
Set-UV 'Software\Microsoft\Windows\CurrentVersion\Themes\Personalize' 'AppsUseLightTheme' 0
Set-UV 'Software\Microsoft\Windows\CurrentVersion\Themes\Personalize' 'SystemUsesLightTheme' 0
Write-Host "[*] Applying search / Bing / highlights settings"
Set-UV 'Software\Policies\Microsoft\Windows\Explorer' 'DisableSearchBoxSuggestions' 1
Set-UV 'Software\Microsoft\Windows\CurrentVersion\SearchSettings' 'IsDynamicSearchBoxEnabled' 0
Write-Host "[*] Applying Spotlight settings"
Set-UV 'Software\Policies\Microsoft\Windows\CloudContent' 'DisableSpotlightCollectionOnDesktop' 1
Set-UV 'Software\Policies\Microsoft\Windows\CloudContent' 'DisableWindowsSpotlightFeatures' 1
Write-Host ""
Write-Host "[OK] UI settings written to $hivePath"
}
finally {
if ($weLoaded) {
# Release any handles we might be holding on to
[GC]::Collect(); [GC]::WaitForPendingFinalizers()
[GC]::Collect(); [GC]::WaitForPendingFinalizers()
Start-Sleep -Milliseconds 500
& reg.exe unload $hivePath 2>&1 | Out-Null
if ($LASTEXITCODE -eq 0) {
Write-Host "[*] Unloaded $hivePath"
} else {
Write-Host "[!] reg unload returned $LASTEXITCODE — hive may still be held. Check with: reg query HKU\$sid"
}
}
}
Write-Host ""
Write-Host "Note: changes take effect when '$TargetUser' next logs in, or after explorer.exe restart if already logged in."

View File

@@ -0,0 +1,145 @@
[Console]::OutputEncoding = [Text.Encoding]::UTF8
$ErrorActionPreference = 'SilentlyContinue'
function Section($title) {
Write-Host ''
Write-Host ('=' * 8) $title ('=' * 8) -ForegroundColor Green
}
function StatusCheck($description, $condition, $recommendation = "") {
$status = if ($condition) { "✅ OK" } else { "❌ NOT OK" }
Write-Host "$description`: $status" -ForegroundColor $(if ($condition) { "Green" } else { "Red" })
if (-not $condition -and $recommendation) {
Write-Host " 💡 $recommendation" -ForegroundColor Yellow
}
}
Section "WinRM Service Status"
$winrmService = Get-Service -Name WinRM -ErrorAction SilentlyContinue
if ($winrmService) {
StatusCheck "WinRM Service Exists" $true
StatusCheck "WinRM Service Running" ($winrmService.Status -eq "Running") "Run: Start-Service WinRM"
StatusCheck "WinRM Service Startup" ($winrmService.StartType -eq "Automatic") "Run: Set-Service WinRM -StartupType Automatic"
} else {
StatusCheck "WinRM Service Exists" $false "WinRM service not found - this is unusual for Windows 10/11"
}
Section "WinRM Configuration"
try {
$winrmConfig = winrm get winrm/config 2>$null
StatusCheck "WinRM Config Accessible" ($winrmConfig -ne $null) "Run: winrm quickconfig -quiet"
if ($winrmConfig) {
# Parse basic config
$allowUnencrypted = ($winrmConfig | Select-String "AllowUnencrypted = true") -ne $null
$basicAuth = ($winrmConfig | Select-String "Basic = true") -ne $null
StatusCheck "Allow Unencrypted" $allowUnencrypted "For testing: winrm set winrm/config/service @{AllowUnencrypted=`"true`"}"
StatusCheck "Basic Auth Enabled" $basicAuth "Run: winrm set winrm/config/service/auth @{Basic=`"true`"}"
}
} catch {
StatusCheck "WinRM Config Accessible" $false "Run: winrm quickconfig -quiet"
}
Section "WinRM Listeners"
try {
$listeners = winrm enumerate winrm/config/listener 2>$null
$httpListener = ($listeners | Select-String "Transport = HTTP") -ne $null
$httpsListener = ($listeners | Select-String "Transport = HTTPS") -ne $null
StatusCheck "HTTP Listener (Port 5985)" $httpListener "Run: winrm create winrm/config/listener?Address=*+Transport=HTTP"
StatusCheck "HTTPS Listener (Port 5986)" $httpsListener "Optional: Create HTTPS listener for secure connection"
if ($listeners) {
Write-Host "`nListener Details:"
Write-Host $listeners
}
} catch {
StatusCheck "WinRM Listeners Available" $false "Run: winrm quickconfig -quiet"
}
Section "PowerShell Remoting"
try {
$psSessionConfig = Get-PSSessionConfiguration -Name Microsoft.PowerShell -ErrorAction SilentlyContinue
StatusCheck "PowerShell Remoting Enabled" ($psSessionConfig -ne $null) "Run: Enable-PSRemoting -Force"
if ($psSessionConfig) {
StatusCheck "PS Remoting Not Disabled" ($psSessionConfig.Permission -notmatch "AccessDenied") "Check session configuration permissions"
}
} catch {
StatusCheck "PowerShell Remoting Accessible" $false "Run: Enable-PSRemoting -Force"
}
Section "Firewall Rules"
$firewallRules = Get-NetFirewallRule -DisplayGroup "*Remote Management*" -ErrorAction SilentlyContinue
$winrmHttpRule = $firewallRules | Where-Object { $_.DisplayName -match "Windows Remote Management.*HTTP" -and $_.Enabled -eq $true }
$winrmHttpsRule = $firewallRules | Where-Object { $_.DisplayName -match "Windows Remote Management.*HTTPS" -and $_.Enabled -eq $true }
StatusCheck "WinRM HTTP Firewall Rule" ($winrmHttpRule -ne $null) "Run: Enable-NetFirewallRule -DisplayGroup 'Windows Remote Management'"
StatusCheck "WinRM HTTPS Firewall Rule" ($winrmHttpsRule -ne $null) "Optional for HTTPS"
# Show current firewall rules
if ($firewallRules) {
Write-Host "`nCurrent WinRM Firewall Rules:"
$firewallRules | Select-Object DisplayName, Enabled, Direction, Action | Format-Table -AutoSize
}
Section "Network Connectivity Test"
$currentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
$computerName = $env:COMPUTERNAME
$ipAddresses = Get-NetIPAddress -AddressFamily IPv4 | Where-Object { $_.InterfaceAlias -notmatch 'Loopback' } | Select-Object -ExpandProperty IPAddress
Write-Host "Current User: $currentUser"
Write-Host "Computer Name: $computerName"
Write-Host "IP Addresses: $($ipAddresses -join ', ')"
# Test local WinRM connectivity
try {
$testSession = New-PSSession -ComputerName localhost -ErrorAction Stop
Remove-PSSession $testSession -ErrorAction SilentlyContinue
StatusCheck "Local WinRM Test" $true
} catch {
StatusCheck "Local WinRM Test" $false "Local connection failed: $($_.Exception.Message)"
}
Section "Authentication Methods"
try {
$authConfig = winrm get winrm/config/service/auth 2>$null
if ($authConfig) {
Write-Host "Available Authentication Methods:"
Write-Host $authConfig
}
} catch {
Write-Host "Could not retrieve authentication configuration"
}
Section "Recommended Actions"
Write-Host "If WinRM is not properly configured, run these commands as Administrator:" -ForegroundColor Cyan
Write-Host ""
Write-Host "# Enable PowerShell Remoting and WinRM" -ForegroundColor Yellow
Write-Host "Enable-PSRemoting -Force"
Write-Host "winrm quickconfig -quiet"
Write-Host ""
Write-Host "# Configure basic authentication (for testing)" -ForegroundColor Yellow
Write-Host "winrm set winrm/config/service/auth '@{Basic=`"true`"}'"
Write-Host "winrm set winrm/config/service '@{AllowUnencrypted=`"true`"}'"
Write-Host ""
Write-Host "# Enable firewall rules" -ForegroundColor Yellow
Write-Host "Enable-NetFirewallRule -DisplayGroup 'Windows Remote Management'"
Write-Host ""
Write-Host "# Test from remote machine:" -ForegroundColor Yellow
Write-Host "Test-WSMan -ComputerName $($ipAddresses[0]) -Authentication Basic"
Section "Current Status Summary"
$winrmRunning = $winrmService -and ($winrmService.Status -eq "Running")
$configExists = try { winrm get winrm/config >$null 2>&1; $true } catch { $false }
$listenersExist = try { winrm enumerate winrm/config/listener >$null 2>&1; $true } catch { $false }
$firewallEnabled = ($winrmHttpRule -ne $null)
if ($winrmRunning -and $configExists -and $listenersExist -and $firewallEnabled) {
Write-Host "🎉 WinRM appears to be ready for remote connections!" -ForegroundColor Green
} elseif ($winrmRunning -and $configExists) {
Write-Host "⚠️ WinRM is partially configured - may need firewall or listener setup" -ForegroundColor Yellow
} else {
Write-Host "❌ WinRM requires configuration before remote access will work" -ForegroundColor Red
}

View File

@@ -0,0 +1,119 @@
[Console]::OutputEncoding = [Text.Encoding]::UTF8
$ErrorActionPreference = 'Continue'
Write-Host "[*] Cleaning up download shortcuts and fixing winget"
# Remove download shortcuts
$desktopPath = "C:\Users\User\Desktop"
$shortcutsToRemove = @(
"Download-Chrome.url",
"Download-7-Zip.url",
"Download-AnyDesk.url",
"Download-LINE.url",
"Download-Adobe-Reader.url",
"Installation-Instructions.txt"
)
Write-Host "[1] Removing download shortcuts..."
foreach ($shortcut in $shortcutsToRemove) {
$filePath = Join-Path $desktopPath $shortcut
if (Test-Path $filePath) {
Remove-Item $filePath -Force
Write-Host " Removed: $shortcut"
}
}
Write-Host "[2] Checking winget status..."
# Check if winget is available
try {
$wingetVersion = & winget --version 2>&1
if ($LASTEXITCODE -eq 0) {
Write-Host " [OK] winget is available: $wingetVersion"
} else {
Write-Host " [!] winget command failed"
throw "winget not working"
}
} catch {
Write-Host " [!] winget not found or not working"
Write-Host "[3] Installing/Updating winget..."
# Method 1: Try to install App Installer (contains winget)
try {
Write-Host " Attempting to install Microsoft App Installer..."
# Download and install App Installer
$appInstallerUrl = "https://github.com/microsoft/winget-cli/releases/latest/download/Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle"
$downloadPath = "$env:TEMP\AppInstaller.msixbundle"
Invoke-WebRequest -Uri $appInstallerUrl -OutFile $downloadPath -UseBasicParsing
# Install the package
Add-AppxPackage -Path $downloadPath
Write-Host " [OK] App Installer installed"
# Clean up
Remove-Item $downloadPath -Force -ErrorAction SilentlyContinue
} catch {
Write-Host " [!] Failed to install App Installer: $($_.Exception.Message)"
# Method 2: Try alternative approach
Write-Host " Trying alternative winget installation..."
try {
# Check Windows version and suggest manual installation
$osVersion = [System.Environment]::OSVersion.Version
Write-Host " Windows Version: $osVersion"
if ($osVersion.Major -ge 10 -and $osVersion.Build -ge 17763) {
Write-Host " [INFO] Windows version supports winget"
Write-Host " [ACTION] Manual steps required:"
Write-Host " 1. Open Microsoft Store"
Write-Host " 2. Search for 'App Installer'"
Write-Host " 3. Install/Update App Installer"
Write-Host " 4. Restart PowerShell session"
} else {
Write-Host " [!] Windows version may not support winget"
Write-Host " Consider updating Windows or using manual installation"
}
} catch {
Write-Host " [!] Could not determine Windows version"
}
}
}
Write-Host "[4] Final winget verification..."
# Wait a moment and test again
Start-Sleep -Seconds 3
try {
$wingetTest = & winget list --source winget 2>&1
if ($LASTEXITCODE -eq 0) {
Write-Host " [OK] winget is working properly"
Write-Host " [INFO] Ready for application installation"
# Test a simple winget operation
Write-Host "[5] Testing winget functionality..."
$testResult = & winget search "7zip.7zip" 2>&1
if ($LASTEXITCODE -eq 0) {
Write-Host " [OK] winget search working"
} else {
Write-Host " [!] winget search failed, may need source configuration"
}
} else {
Write-Host " [!] winget still not working properly"
Write-Host " Output: $wingetTest"
}
} catch {
Write-Host " [!] winget verification failed: $($_.Exception.Message)"
}
Write-Host ""
Write-Host "Cleanup and winget setup completed!"
Write-Host "If winget is working, we can proceed with automated installation."

View File

@@ -0,0 +1,112 @@
param(
[string]$TargetUser = 'User'
)
[Console]::OutputEncoding = [Text.Encoding]::UTF8
$ErrorActionPreference = 'Stop'
# Resolve target user SID
$sid = (New-Object System.Security.Principal.NTAccount($TargetUser)).Translate([System.Security.Principal.SecurityIdentifier]).Value
$hivePath = "HKEY_USERS\$sid"
$regBase = "Registry::$hivePath"
$ntuserDat = "C:\Users\$TargetUser\NTUSER.DAT"
$weLoaded = $false
if (-not (Test-Path $regBase)) {
if (-not (Test-Path $ntuserDat)) {
# Try alternate casing (NTFS is case-insensitive but PS sees the literal case)
$alt = Get-Item "C:\Users\*" | Where-Object { $_.Name -ieq $TargetUser } | Select-Object -First 1
if ($alt) { $ntuserDat = Join-Path $alt.FullName 'NTUSER.DAT' }
}
if (-not (Test-Path $ntuserDat)) { throw "NTUSER.DAT not found for $TargetUser" }
Write-Host "[*] Loading $ntuserDat"
& reg.exe load $hivePath $ntuserDat | Out-Null
if ($LASTEXITCODE -ne 0) { throw "reg load failed" }
$weLoaded = $true
}
try {
# ---------- 1. Add en-US to language list as FIRST language (default) ----------
# This targets the CURRENT user running this script. For the target user, we
# write the preload keys directly into their hive.
Write-Host "[*] Setting target user's keyboard preload (en-US first, zh-TW second)"
$preloadPath = "$regBase\Keyboard Layout\Preload"
if (-not (Test-Path $preloadPath)) { New-Item -Path $preloadPath -Force | Out-Null }
# 00000409 = English (US); 00000404 = Chinese (Traditional, Taiwan)
New-ItemProperty -Path $preloadPath -Name '1' -Value '00000409' -PropertyType String -Force | Out-Null
New-ItemProperty -Path $preloadPath -Name '2' -Value '00000404' -PropertyType String -Force | Out-Null
$substitutesPath = "$regBase\Keyboard Layout\Substitutes"
if (Test-Path $substitutesPath) {
Remove-Item $substitutesPath -Recurse -Force
}
# ---------- 2. Set Chinese IME to default to English (alphanumeric) mode ----------
Write-Host "[*] Setting Microsoft Bopomofo to default English mode"
$chtPath = "$regBase\Software\Microsoft\InputMethod\Settings\CHT"
if (-not (Test-Path $chtPath)) { New-Item -Path $chtPath -Force | Out-Null }
# 0 = default English mode, 1 = default Chinese mode
New-ItemProperty -Path $chtPath -Name 'Enable Default Input Mode' -Value 0 -PropertyType DWord -Force | Out-Null
# ---------- 3. Set Bopomofo's Chinese/English switch hotkey to Ctrl+Space ----------
# Microsoft Bopomofo exposes this option in its Settings UI:
# Shift (default) | Ctrl + Space | Caps Lock
# The registry value is 'Enable Ctrl Space Switch Chinese English' (boolean-ish).
Write-Host "[*] Setting Ctrl+Space as Chinese/English switch for MS Bopomofo"
New-ItemProperty -Path $chtPath -Name 'Enable Ctrl Space Switch Chinese English' -Value 1 -PropertyType DWord -Force | Out-Null
# Also disable Shift as the switch (optional, prevents confusion)
New-ItemProperty -Path $chtPath -Name 'Enable Shift Chinese English' -Value 0 -PropertyType DWord -Force | Out-Null
# ---------- 4. Disable OS-level Ctrl+Shift / Alt+Shift language toggle ----------
# So Ctrl+Space is the only thing that triggers language switching.
Write-Host "[*] Disabling OS-level Language/Layout hotkeys"
$togglePath = "$regBase\Keyboard Layout\Toggle"
if (-not (Test-Path $togglePath)) { New-Item -Path $togglePath -Force | Out-Null }
# Values: 1 = Ctrl+Shift, 2 = Left Alt+Shift, 3 = Grave Accent, 4 = Not assigned
New-ItemProperty -Path $togglePath -Name 'Hotkey' -Value '3' -PropertyType String -Force | Out-Null
New-ItemProperty -Path $togglePath -Name 'Language Hotkey' -Value '3' -PropertyType String -Force | Out-Null
New-ItemProperty -Path $togglePath -Name 'Layout Hotkey' -Value '3' -PropertyType String -Force | Out-Null
# ---------- 5. Tell the language subsystem en-US is the default ----------
# Remove user-profile language forcing so that Preload order is respected
$userProfileLangPath = "$regBase\Control Panel\International\User Profile"
if (Test-Path $userProfileLangPath) {
$langs = (Get-ItemProperty $userProfileLangPath).Languages
if ($langs) {
# Prepend en-US to the language list
$newLangs = @('en-US') + ($langs | Where-Object { $_ -ne 'en-US' })
New-ItemProperty -Path $userProfileLangPath -Name 'Languages' -Value $newLangs -PropertyType MultiString -Force | Out-Null
Write-Host "[*] Updated user-profile language list: $($newLangs -join ', ')"
}
}
# Ensure per-language subkeys exist
$enUSPath = "$userProfileLangPath\en-US"
if (-not (Test-Path $enUSPath)) { New-Item -Path $enUSPath -Force | Out-Null }
# CachedLanguageName is cosmetic but prevents re-detection flakiness
New-ItemProperty -Path $enUSPath -Name '0409:00000409' -Value 1 -PropertyType DWord -Force | Out-Null
Write-Host ""
Write-Host "[OK] IME configured for '$TargetUser'"
Write-Host "Summary:"
Write-Host " - Default input: English (US) keyboard"
Write-Host " - Microsoft Bopomofo: starts in English (alphanumeric) mode"
Write-Host " - Ctrl+Space: toggles between English / Chinese within Bopomofo"
Write-Host " - OS-level language hotkeys (Ctrl+Shift / Alt+Shift): disabled"
}
finally {
if ($weLoaded) {
[GC]::Collect(); [GC]::WaitForPendingFinalizers()
[GC]::Collect(); [GC]::WaitForPendingFinalizers()
Start-Sleep -Milliseconds 500
& reg.exe unload $hivePath 2>&1 | Out-Null
if ($LASTEXITCODE -eq 0) { Write-Host "[*] Unloaded $hivePath" }
else { Write-Host "[!] reg unload returned $LASTEXITCODE" }
}
}
Write-Host ""
Write-Host "Note: Settings apply on '$TargetUser' next login. If Bopomofo doesn't pick up"
Write-Host "Ctrl+Space automatically, open 'Microsoft Bopomofo settings' -> 'Keys' and"
Write-Host "confirm 'Chinese/English switch' = Ctrl+Space (this registry write should do it)."

View File

@@ -0,0 +1,94 @@
[Console]::OutputEncoding = [Text.Encoding]::UTF8
Write-Host "[*] Creating download shortcuts for essential applications"
$desktopPath = "C:\Users\User\Desktop"
# Application download links
$apps = @(
@{
Name = "Google Chrome"
Url = "https://dl.google.com/chrome/install/GoogleChromeStandaloneEnterprise64.msi"
FileName = "Download-Chrome.url"
},
@{
Name = "7-Zip"
Url = "https://www.7-zip.org/download.html"
FileName = "Download-7-Zip.url"
},
@{
Name = "AnyDesk"
Url = "https://anydesk.com/download"
FileName = "Download-AnyDesk.url"
},
@{
Name = "LINE"
Url = "https://line.me/download"
FileName = "Download-LINE.url"
},
@{
Name = "Adobe Reader"
Url = "https://get.adobe.com/reader/"
FileName = "Download-Adobe-Reader.url"
}
)
Write-Host "Creating download shortcuts on User desktop..."
foreach ($app in $apps) {
$shortcutContent = @"
[InternetShortcut]
URL=$($app.Url)
IconIndex=0
"@
$filePath = Join-Path $desktopPath $app.FileName
$shortcutContent | Out-File $filePath -Encoding ASCII
Write-Host " Created: $($app.FileName)"
}
# Create installation instructions
$instructions = @"
=== Application Installation Instructions ===
1. Google Chrome:
- Double-click Download-Chrome.url
- Download the .msi file
- Run the installer (silent install)
2. 7-Zip:
- Double-click Download-7-Zip.url
- Download the x64 .msi version
- Run installer
3. AnyDesk:
- Double-click Download-AnyDesk.url
- Download AnyDesk
- Run installer
4. LINE:
- Double-click Download-LINE.url
- Download LINE for Windows
- Run installer
5. Adobe Reader:
- Double-click Download-Adobe-Reader.url
- Download Adobe Acrobat Reader
- Run installer
All applications will be installed for all users.
"@
$instructionsPath = Join-Path $desktopPath "Installation-Instructions.txt"
$instructions | Out-File $instructionsPath -Encoding UTF8
Write-Host ""
Write-Host "[OK] Download shortcuts created on User desktop:"
Write-Host " - Download-Chrome.url"
Write-Host " - Download-7-Zip.url"
Write-Host " - Download-AnyDesk.url"
Write-Host " - Download-LINE.url"
Write-Host " - Download-Adobe-Reader.url"
Write-Host " - Installation-Instructions.txt"
Write-Host ""
Write-Host "User can now easily download and install applications manually."

View File

@@ -0,0 +1,86 @@
[Console]::OutputEncoding = [Text.Encoding]::UTF8
$ErrorActionPreference = 'SilentlyContinue'
function Section($title) {
Write-Host ''
Write-Host ('=' * 8) $title ('=' * 8) -ForegroundColor Green
}
Section "WinRM Network Diagnostics"
# Check if WinRM is running
$winrmService = Get-Service WinRM
Write-Host "WinRM Service Status: $($winrmService.Status)" -ForegroundColor $(if($winrmService.Status -eq 'Running') {'Green'} else {'Red'})
# Check WinRM listeners
Section "WinRM Listeners"
try {
$listeners = winrm enumerate winrm/config/listener
Write-Host $listeners
} catch {
Write-Host "Failed to enumerate listeners: $_" -ForegroundColor Red
}
# Check firewall rules specifically for WinRM
Section "Firewall Rules for WinRM"
$winrmRules = Get-NetFirewallRule | Where-Object { $_.DisplayName -like "*WinRM*" -or $_.DisplayName -like "*Windows Remote Management*" }
foreach ($rule in $winrmRules) {
$ruleDetails = Get-NetFirewallPortFilter -AssociatedNetFirewallRule $rule -ErrorAction SilentlyContinue
$color = if ($rule.Enabled) { 'Green' } else { 'Red' }
Write-Host "$($rule.DisplayName): $($rule.Enabled) [$($rule.Direction)] Port: $($ruleDetails.LocalPort)" -ForegroundColor $color
}
# Check network connections on port 5985
Section "Network Connections on Port 5985"
$connections = Get-NetTCPConnection -LocalPort 5985 -ErrorAction SilentlyContinue
if ($connections) {
$connections | Select-Object LocalAddress, LocalPort, State, OwningProcess | Format-Table -AutoSize
} else {
Write-Host "No connections found on port 5985" -ForegroundColor Red
}
# Check listening ports
Section "Listening Ports (including 5985)"
Get-NetTCPConnection -State Listen | Where-Object { $_.LocalPort -in @(22, 5985, 5986) } |
Select-Object LocalAddress, LocalPort, State, OwningProcess | Format-Table -AutoSize
# Get detailed WinRM configuration
Section "Detailed WinRM Configuration"
try {
Write-Host "Service Configuration:" -ForegroundColor Yellow
winrm get winrm/config/service
Write-Host "`nListener Configuration:" -ForegroundColor Yellow
winrm get winrm/config/listener?Address=*+Transport=HTTP
} catch {
Write-Host "Failed to get WinRM config: $_" -ForegroundColor Red
}
# Test local WinRM connection
Section "Local WinRM Connection Test"
try {
$testResult = Test-WSMan -ComputerName localhost -ErrorAction Stop
Write-Host "✅ Local WinRM test successful" -ForegroundColor Green
} catch {
Write-Host "❌ Local WinRM test failed: $_" -ForegroundColor Red
}
# Network interface information
Section "Network Interfaces"
Get-NetIPAddress -AddressFamily IPv4 | Where-Object { $_.InterfaceAlias -notmatch 'Loopback' } |
Select-Object InterfaceAlias, IPAddress, PrefixLength | Format-Table -AutoSize
# Proposed fixes
Section "Recommended Fixes"
Write-Host "1. Enable WinRM firewall rules:" -ForegroundColor Yellow
Write-Host " Enable-NetFirewallRule -DisplayName 'Windows Remote Management (HTTP-In)'" -ForegroundColor White
Write-Host "`n2. Set AllowUnencrypted to true:" -ForegroundColor Yellow
Write-Host " winrm set winrm/config/service '@{AllowUnencrypted=`"true`"}'" -ForegroundColor White
Write-Host "`n3. Ensure listener is on all interfaces:" -ForegroundColor Yellow
Write-Host " winrm set winrm/config/listener?Address=*+Transport=HTTP '@{Enabled=`"true`"}'" -ForegroundColor White
Write-Host "`n4. Test from remote after fixes:" -ForegroundColor Yellow
Write-Host " Test-WSMan -ComputerName 192.168.88.108 -UseSSL:`$false" -ForegroundColor White

View File

@@ -0,0 +1,83 @@
[Console]::OutputEncoding = [Text.Encoding]::UTF8
$ErrorActionPreference = 'Continue'
Write-Host "[*] Diagnosing winget configuration and connectivity"
Write-Host ""
Write-Host "[1] Checking winget version and status..."
try {
$wingetVersion = & winget --version
Write-Host " winget version: $wingetVersion"
} catch {
Write-Host " [!] winget command failed"
}
Write-Host ""
Write-Host "[2] Checking winget sources..."
try {
$sources = & winget source list
Write-Host " winget sources:"
Write-Host "$sources"
} catch {
Write-Host " [!] Failed to list winget sources"
}
Write-Host ""
Write-Host "[3] Testing network connectivity..."
$testUrls = @(
"github.com",
"cdn.winget.microsoft.com",
"storeedgefd.dsx.mp.microsoft.com"
)
foreach ($url in $testUrls) {
try {
$testResult = Test-NetConnection -ComputerName $url -Port 443 -WarningAction SilentlyContinue
if ($testResult.TcpTestSucceeded) {
Write-Host " [OK] $url - Accessible"
} else {
Write-Host " [!] $url - Not accessible"
}
} catch {
Write-Host " [!] $url - Test failed"
}
}
Write-Host ""
Write-Host "[4] Testing simple winget search..."
try {
Write-Host " Searching for Chrome..."
$searchResult = & winget search "Google.Chrome" --exact
Write-Host " Search result: $searchResult"
} catch {
Write-Host " [!] winget search failed"
}
Write-Host ""
Write-Host "[5] Checking Windows version compatibility..."
$windowsVersion = Get-ComputerInfo | Select-Object WindowsProductName, WindowsVersion, WindowsBuildLabEx
Write-Host " OS: $($windowsVersion.WindowsProductName)"
Write-Host " Version: $($windowsVersion.WindowsVersion)"
Write-Host " Build: $($windowsVersion.WindowsBuildLabEx)"
Write-Host ""
Write-Host "[6] Testing manual installation with verbose output..."
Write-Host " Attempting to install 7-Zip with verbose logging..."
try {
$installTest = & winget install 7zip.7zip --accept-package-agreements --accept-source-agreements --verbose 2>&1
Write-Host " Install output:"
Write-Host "$installTest"
} catch {
Write-Host " [!] Manual install test failed: $($_.Exception.Message)"
}
Write-Host ""
Write-Host "Diagnosis completed!"
Write-Host ""
Write-Host "Possible solutions based on findings:"
Write-Host "1. If network connectivity issues: Configure proxy or firewall"
Write-Host "2. If source issues: Reset winget sources"
Write-Host "3. If permissions issues: Run as Administrator"
Write-Host "4. If Windows version issues: Update Windows or use manual installation"

View File

@@ -0,0 +1,155 @@
[Console]::OutputEncoding = [Text.Encoding]::UTF8
$ErrorActionPreference = 'Stop'
function Section($title) {
Write-Host ''
Write-Host ('=' * 8) $title ('=' * 8) -ForegroundColor Green
}
function StatusUpdate($message) {
Write-Host "$message" -ForegroundColor Green
}
function WarningUpdate($message) {
Write-Host "⚠️ $message" -ForegroundColor Yellow
}
Write-Host "Starting WinRM Configuration..." -ForegroundColor Cyan
Write-Host "This script will configure WinRM for remote management." -ForegroundColor Cyan
Write-Host ""
# Check if running as Administrator
$currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
$isAdmin = $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not $isAdmin) {
Write-Host "❌ ERROR: This script must be run as Administrator" -ForegroundColor Red
Write-Host "Please run PowerShell as Administrator and try again." -ForegroundColor Red
exit 1
}
StatusUpdate "Running as Administrator"
Section "Enable PowerShell Remoting"
try {
Enable-PSRemoting -Force -SkipNetworkProfileCheck | Out-Null
StatusUpdate "PowerShell Remoting enabled"
} catch {
WarningUpdate "PowerShell Remoting may already be enabled: $($_.Exception.Message)"
}
Section "Configure WinRM Service"
try {
# Ensure WinRM service is set to automatic startup
Set-Service -Name WinRM -StartupType Automatic
Start-Service -Name WinRM
StatusUpdate "WinRM service configured and started"
} catch {
WarningUpdate "WinRM service configuration: $($_.Exception.Message)"
}
Section "Run WinRM Quick Configuration"
try {
$quickConfigOutput = cmd /c "winrm quickconfig -quiet" 2>&1
StatusUpdate "WinRM quick configuration completed"
} catch {
WarningUpdate "WinRM quickconfig: $($_.Exception.Message)"
}
Section "Configure Authentication Methods"
try {
# Enable Basic authentication for simplicity (can be disabled later for production)
cmd /c 'winrm set winrm/config/service/auth @{Basic="true"}' | Out-Null
StatusUpdate "Basic authentication enabled"
# Allow unencrypted traffic for HTTP (can be disabled in production)
cmd /c 'winrm set winrm/config/service @{AllowUnencrypted="true"}' | Out-Null
StatusUpdate "Unencrypted communication allowed (for HTTP testing)"
} catch {
WarningUpdate "Authentication configuration: $($_.Exception.Message)"
}
Section "Configure Firewall Rules"
try {
# Enable Windows Remote Management firewall rules
Enable-NetFirewallRule -DisplayGroup "Windows Remote Management" -ErrorAction SilentlyContinue
StatusUpdate "Windows Remote Management firewall rules enabled"
} catch {
WarningUpdate "Firewall configuration: $($_.Exception.Message)"
}
Section "Create HTTP Listener (if needed)"
try {
# Check if HTTP listener exists
$httpListener = winrm enumerate winrm/config/listener | Select-String "Transport = HTTP"
if (-not $httpListener) {
winrm create winrm/config/listener?Address=*+Transport=HTTP | Out-Null
StatusUpdate "HTTP listener created on port 5985"
} else {
StatusUpdate "HTTP listener already exists"
}
} catch {
WarningUpdate "HTTP listener configuration: $($_.Exception.Message)"
}
Section "Test Local Connection"
try {
$testSession = New-PSSession -ComputerName localhost -ErrorAction Stop
Remove-PSSession $testSession -ErrorAction SilentlyContinue
StatusUpdate "Local WinRM connection test successful"
} catch {
WarningUpdate "Local connection test failed: $($_.Exception.Message)"
Write-Host " This may be normal if additional configuration is needed"
}
Section "Configuration Summary"
Write-Host ""
Write-Host "WinRM has been configured with the following settings:" -ForegroundColor Cyan
Write-Host ""
# Display current configuration
try {
Write-Host "Service Status:" -ForegroundColor Yellow
Get-Service WinRM | Select-Object Name, Status, StartType | Format-List
Write-Host "Listeners:" -ForegroundColor Yellow
winrm enumerate winrm/config/listener
Write-Host "Authentication Methods:" -ForegroundColor Yellow
winrm get winrm/config/service/auth
Write-Host "Firewall Rules:" -ForegroundColor Yellow
Get-NetFirewallRule -DisplayGroup "*Remote Management*" | Where-Object Enabled -eq $true |
Select-Object DisplayName, Direction, Action | Format-Table -AutoSize
} catch {
Write-Host "Could not retrieve full configuration details"
}
Section "Connection Information"
$ipAddresses = Get-NetIPAddress -AddressFamily IPv4 | Where-Object { $_.InterfaceAlias -notmatch 'Loopback' } | Select-Object -ExpandProperty IPAddress
$computerName = $env:COMPUTERNAME
Write-Host "Computer Name: $computerName" -ForegroundColor Cyan
Write-Host "IP Addresses: $($ipAddresses -join ', ')" -ForegroundColor Cyan
Write-Host ""
Write-Host "To test from a remote machine, use:" -ForegroundColor Yellow
Write-Host "Test-WSMan -ComputerName $($ipAddresses[0])" -ForegroundColor White
Write-Host " or"
Write-Host "Test-WSMan -ComputerName $computerName" -ForegroundColor White
Write-Host ""
Write-Host "For PowerShell remoting:" -ForegroundColor Yellow
Write-Host "`$session = New-PSSession -ComputerName $($ipAddresses[0]) -Credential (Get-Credential)" -ForegroundColor White
Section "Security Notes"
Write-Host "⚠️ SECURITY CONSIDERATIONS:" -ForegroundColor Yellow
Write-Host ""
Write-Host "1. Basic authentication and unencrypted communication are enabled for testing" -ForegroundColor Yellow
Write-Host "2. For production use, consider:" -ForegroundColor Yellow
Write-Host " - Disabling Basic auth: winrm set winrm/config/service/auth @{Basic=`"false`"}" -ForegroundColor White
Write-Host " - Disabling unencrypted: winrm set winrm/config/service @{AllowUnencrypted=`"false`"}" -ForegroundColor White
Write-Host " - Setting up HTTPS listener with proper certificates" -ForegroundColor White
Write-Host " - Using Kerberos authentication in domain environments" -ForegroundColor White
Write-Host ""
Write-Host "🎉 WinRM configuration completed!" -ForegroundColor Green

View File

@@ -0,0 +1,36 @@
[Console]::OutputEncoding = [Text.Encoding]::UTF8
$ErrorActionPreference = 'Stop'
$ruleName = 'SSH TCP 22 (Allow Inbound)'
# Idempotent: remove any existing rule with the same display name, then recreate.
Get-NetFirewallRule -DisplayName $ruleName -ErrorAction SilentlyContinue | Remove-NetFirewallRule
New-NetFirewallRule `
-DisplayName $ruleName `
-Description 'Allow inbound SSH on TCP 22 for all firewall profiles (Domain, Private, Public)' `
-Direction Inbound `
-Protocol TCP `
-LocalPort 22 `
-Action Allow `
-Profile Any `
-Enabled True | Out-Null
Write-Host "[*] Re-enabling firewall profiles (Domain, Private, Public)"
Set-NetFirewallProfile -Profile Domain,Private,Public -Enabled True
Write-Host ""
Write-Host "=== Rule ==="
Get-NetFirewallRule -DisplayName $ruleName |
Select-Object DisplayName,Enabled,Direction,Action,Profile |
Format-List
Write-Host "=== Port filter ==="
Get-NetFirewallRule -DisplayName $ruleName | Get-NetFirewallPortFilter |
Format-List Protocol,LocalPort
Write-Host "=== Profile state ==="
Get-NetFirewallProfile | Select-Object Name,Enabled,DefaultInboundAction,DefaultOutboundAction |
Format-Table -AutoSize
Write-Host "[OK] SSH 22 is now permanently allowed across all profiles."

View File

@@ -0,0 +1,62 @@
[Console]::OutputEncoding = [Text.Encoding]::UTF8
$ErrorActionPreference = 'Stop'
function Section($title) {
Write-Host ''
Write-Host ('=' * 8) $title ('=' * 8) -ForegroundColor Green
}
function StatusUpdate($message) {
Write-Host "$message" -ForegroundColor Green
}
function WarningUpdate($message) {
Write-Host "⚠️ $message" -ForegroundColor Yellow
}
Write-Host "Fixing remaining WinRM configuration issues..." -ForegroundColor Cyan
Section "Fix Allow Unencrypted Setting"
try {
cmd /c 'winrm set winrm/config/service @{AllowUnencrypted="true"}' | Out-Null
StatusUpdate "Allow unencrypted communication enabled"
} catch {
WarningUpdate "Failed to set AllowUnencrypted: $($_.Exception.Message)"
}
Section "Enable WinRM Firewall Rules"
try {
Enable-NetFirewallRule -DisplayGroup "Windows Remote Management" -ErrorAction SilentlyContinue
StatusUpdate "WinRM firewall rules enabled"
# Show enabled WinRM rules
$winrmRules = Get-NetFirewallRule -DisplayGroup "*Remote Management*" | Where-Object Enabled -eq $true
Write-Host "Enabled WinRM firewall rules:" -ForegroundColor Yellow
$winrmRules | Select-Object DisplayName, Direction, Action | Format-Table -AutoSize
} catch {
WarningUpdate "Firewall rule configuration: $($_.Exception.Message)"
}
Section "Verify Settings"
try {
Write-Host "Current WinRM Service Configuration:" -ForegroundColor Yellow
winrm get winrm/config/service
Write-Host "`nCurrent Authentication Settings:" -ForegroundColor Yellow
winrm get winrm/config/service/auth
} catch {
WarningUpdate "Could not retrieve configuration: $($_.Exception.Message)"
}
Section "Final Connection Test"
try {
$testSession = New-PSSession -ComputerName localhost -ErrorAction Stop
Remove-PSSession $testSession -ErrorAction SilentlyContinue
StatusUpdate "Final local WinRM test successful"
} catch {
WarningUpdate "Final test failed: $($_.Exception.Message)"
}
Write-Host "`n🎉 WinRM configuration fixes completed!" -ForegroundColor Green

View File

@@ -0,0 +1,122 @@
[Console]::OutputEncoding = [Text.Encoding]::UTF8
$ErrorActionPreference = 'Continue'
Write-Host "[*] Installing applications via direct download"
Write-Host ""
$downloadFolder = "$env:TEMP\AppDownloads"
New-Item -ItemType Directory -Force -Path $downloadFolder | Out-Null
function Install-App {
param(
[string]$Name,
[string]$Url,
[string]$FileName,
[string]$InstallArgs
)
Write-Host "Installing $Name..."
Write-Host " URL: $Url"
$downloadPath = Join-Path $downloadFolder $FileName
try {
Write-Host " Downloading..."
Invoke-WebRequest -Uri $Url -OutFile $downloadPath -UseBasicParsing
Write-Host " Installing..."
if ($FileName.EndsWith(".msi")) {
& msiexec /i $downloadPath $InstallArgs
} else {
& $downloadPath $InstallArgs
}
Write-Host " [OK] $Name installation completed"
return $true
} catch {
Write-Host " [ERROR] Failed to install $Name"
Write-Host " Error: $($_.Exception.Message)"
return $false
}
}
# Application definitions
$apps = @(
@{
Name = "Google Chrome"
Url = "https://dl.google.com/chrome/install/GoogleChromeStandaloneEnterprise64.msi"
FileName = "ChromeSetup.msi"
InstallArgs = "/quiet /norestart"
},
@{
Name = "7-Zip"
Url = "https://www.7-zip.org/a/7z2301-x64.msi"
FileName = "7zip-setup.msi"
InstallArgs = "/quiet /norestart"
},
@{
Name = "AnyDesk"
Url = "https://download.anydesk.com/AnyDesk.msi"
FileName = "AnyDesk.msi"
InstallArgs = "/quiet /norestart"
}
)
$successCount = 0
foreach ($app in $apps) {
if (Install-App -Name $app.Name -Url $app.Url -FileName $app.FileName -InstallArgs $app.InstallArgs) {
$successCount++
}
Write-Host ""
Start-Sleep -Seconds 2
}
# Manual instructions for apps that need special handling
Write-Host "=== Manual Downloads Required ==="
Write-Host ""
Write-Host "LINE:"
Write-Host " Please download from: https://line.me/download"
Write-Host " Or direct: https://desktop.line-scdn.net/win/new/LineInst.exe"
Write-Host ""
Write-Host "Adobe Reader:"
Write-Host " Please download from: https://get.adobe.com/reader/"
Write-Host " Select version for Windows and download"
Write-Host ""
Write-Host "=== Installation Summary ==="
Write-Host "Automatically installed: $successCount / 3 applications"
Write-Host "Manual download required: 2 applications (LINE, Adobe Reader)"
Write-Host ""
# Create desktop shortcuts for manual downloads
$desktopPath = "C:\Users\User\Desktop"
# Create LINE download shortcut
$lineShortcut = @"
[InternetShortcut]
URL=https://line.me/download
IconIndex=0
"@
$lineShortcut | Out-File "$desktopPath\Download-LINE.url" -Encoding ASCII
# Create Adobe Reader download shortcut
$adobeShortcut = @"
[InternetShortcut]
URL=https://get.adobe.com/reader/
IconIndex=0
"@
$adobeShortcut | Out-File "$desktopPath\Download-Adobe-Reader.url" -Encoding ASCII
Write-Host "Created download shortcuts on User desktop:"
Write-Host " - Download-LINE.url"
Write-Host " - Download-Adobe-Reader.url"
# Clean up
Remove-Item $downloadFolder -Recurse -Force -ErrorAction SilentlyContinue
Write-Host ""
Write-Host "Installation process completed!"

View File

@@ -0,0 +1,103 @@
[Console]::OutputEncoding = [Text.Encoding]::UTF8
$ErrorActionPreference = 'Continue'
Write-Host "[*] Installing applications using winget (fixed sources)"
Write-Host ""
# Applications to install with explicit winget source
$apps = @(
@{Name="Google Chrome"; Id="Google.Chrome"},
@{Name="7-Zip"; Id="7zip.7zip"},
@{Name="AnyDesk"; Id="AnyDeskSoftwareGmbH.AnyDesk"},
@{Name="LINE"; Id="LINE.LINE"},
@{Name="Adobe Reader"; Id="Adobe.Acrobat.Reader.64-bit"}
)
$installedCount = 0
$totalApps = $apps.Count
Write-Host "Installing $totalApps applications using winget source..."
Write-Host ""
foreach ($app in $apps) {
Write-Host "[$($installedCount + 1)/$totalApps] Installing $($app.Name)..."
try {
# Install using explicit winget source to avoid msstore certificate issues
Write-Host " Downloading and installing from winget source..."
$installResult = & winget install $app.Id --source winget --accept-package-agreements --accept-source-agreements --silent
if ($LASTEXITCODE -eq 0) {
Write-Host " [OK] $($app.Name) installed successfully"
$installedCount++
} else {
Write-Host " [!] Installation exit code: $LASTEXITCODE"
# Try to verify if it was actually installed despite exit code
Start-Sleep -Seconds 3
$verifyResult = & winget list $app.Id --source winget 2>$null
if ($LASTEXITCODE -eq 0) {
Write-Host " [OK] $($app.Name) appears to be installed"
$installedCount++
} else {
Write-Host " [ERROR] $($app.Name) installation failed"
# Try alternative approach for some apps
if ($app.Name -eq "Google Chrome") {
Write-Host " Trying Chrome enterprise installer..."
try {
$chromeUrl = "https://dl.google.com/chrome/install/GoogleChromeStandaloneEnterprise64.msi"
$chromePath = "$env:TEMP\ChromeSetup.msi"
Invoke-WebRequest -Uri $chromeUrl -OutFile $chromePath -UseBasicParsing
& msiexec /i $chromePath /quiet /norestart
Start-Sleep -Seconds 5
Remove-Item $chromePath -Force -ErrorAction SilentlyContinue
Write-Host " [OK] Chrome installed via direct MSI"
$installedCount++
} catch {
Write-Host " [!] Chrome direct install failed"
}
}
}
}
} catch {
Write-Host " [ERROR] Exception: $($_.Exception.Message)"
}
Write-Host ""
Start-Sleep -Seconds 2
}
Write-Host "=== Installation Summary ==="
Write-Host "Successfully installed: $installedCount / $totalApps applications"
Write-Host ""
# Final verification
Write-Host "Final verification:"
$verificationChecks = @(
@{Name="Chrome"; Paths=@("C:\Program Files\Google\Chrome\Application\chrome.exe", "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe")},
@{Name="7-Zip"; Paths=@("C:\Program Files\7-Zip\7z.exe")},
@{Name="AnyDesk"; Paths=@("C:\Program Files (x86)\AnyDesk\AnyDesk.exe", "C:\Program Files\AnyDesk\AnyDesk.exe")},
@{Name="Adobe Reader"; Paths=@("C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe", "C:\Program Files\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe")},
@{Name="LINE"; Paths=@("C:\Users\$env:USERNAME\AppData\Local\LINE\bin\LineLauncher.exe", "C:\Program Files\LINE\bin\LineLauncher.exe")}
)
foreach ($check in $verificationChecks) {
$found = $false
foreach ($path in $check.Paths) {
if (Test-Path $path) {
Write-Host " [OK] $($check.Name) - Found at $path"
$found = $true
break
}
}
if (-not $found) {
Write-Host " [!] $($check.Name) - Not found"
}
}
Write-Host ""
Write-Host "Installation process completed!"
Write-Host "Note: Some applications may require restart to appear in Start Menu"

View File

@@ -0,0 +1,99 @@
[Console]::OutputEncoding = [Text.Encoding]::UTF8
$ErrorActionPreference = 'Continue'
Write-Host "[*] Installing applications using winget"
Write-Host ""
# Applications to install
$apps = @(
@{Name="Google Chrome"; Id="Google.Chrome"},
@{Name="7-Zip"; Id="7zip.7zip"},
@{Name="AnyDesk"; Id="AnyDeskSoftwareGmbH.AnyDesk"},
@{Name="LINE"; Id="LINE.LINE"},
@{Name="Adobe Reader"; Id="Adobe.Acrobat.Reader.64-bit"}
)
$installedCount = 0
$totalApps = $apps.Count
Write-Host "Installing $totalApps applications..."
Write-Host ""
foreach ($app in $apps) {
Write-Host "[$($installedCount + 1)/$totalApps] Installing $($app.Name)..."
try {
# First check if already installed
$checkResult = & winget list $app.Id 2>$null
if ($LASTEXITCODE -eq 0) {
Write-Host " [SKIP] $($app.Name) already installed"
$installedCount++
continue
}
# Install the application
Write-Host " Downloading and installing..."
$installResult = & winget install $app.Id --accept-package-agreements --accept-source-agreements --silent
if ($LASTEXITCODE -eq 0) {
Write-Host " [OK] $($app.Name) installed successfully"
$installedCount++
} else {
Write-Host " [!] $($app.Name) installation may have failed"
Write-Host " Checking if it was actually installed..."
# Double-check installation
Start-Sleep -Seconds 2
$verifyResult = & winget list $app.Id 2>$null
if ($LASTEXITCODE -eq 0) {
Write-Host " [OK] $($app.Name) verified as installed"
$installedCount++
} else {
Write-Host " [ERROR] $($app.Name) installation failed"
}
}
} catch {
Write-Host " [ERROR] Exception installing $($app.Name): $($_.Exception.Message)"
}
Write-Host ""
Start-Sleep -Seconds 1
}
Write-Host "=== Installation Summary ==="
Write-Host "Successfully processed: $installedCount / $totalApps applications"
Write-Host ""
# Verification
Write-Host "Verification check:"
$verificationPaths = @(
@{Name="Chrome"; Path="C:\Program Files\Google\Chrome\Application\chrome.exe"},
@{Name="7-Zip"; Path="C:\Program Files\7-Zip\7z.exe"},
@{Name="AnyDesk"; Path="C:\Program Files (x86)\AnyDesk\AnyDesk.exe"},
@{Name="Adobe Reader"; Path="C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe"}
)
foreach ($check in $verificationPaths) {
if (Test-Path $check.Path) {
Write-Host " [OK] $($check.Name) - Found"
} else {
Write-Host " [?] $($check.Name) - Not found at expected location"
}
}
# LINE has a different installation path (per-user)
$lineUserPath = "C:\Users\$env:USERNAME\AppData\Local\LINE\bin\LineLauncher.exe"
$lineSystemPath = "C:\Program Files\LINE\bin\LineLauncher.exe"
if ((Test-Path $lineUserPath) -or (Test-Path $lineSystemPath)) {
Write-Host " [OK] LINE - Found"
} else {
Write-Host " [?] LINE - Not found"
}
Write-Host ""
Write-Host "Installation completed!"
Write-Host "Applications may take a few moments to appear in Start Menu."
Write-Host "Some applications may require a system restart to function properly."

View File

@@ -0,0 +1,163 @@
[Console]::OutputEncoding = [Text.Encoding]::UTF8
$ErrorActionPreference = 'Continue'
Write-Host "[*] Installing essential applications for User"
Write-Host "Applications: AnyDesk, LINE, Chrome, 7zip, Adobe Reader"
Write-Host ""
# Function to test if an app is already installed
function Test-AppInstalled {
param([string]$AppName, [string]$ProcessName)
# Check via Get-WmiObject for installed programs
$installed = Get-WmiObject -Class Win32_Product | Where-Object { $_.Name -like "*$AppName*" }
if ($installed) {
Write-Host " $AppName is already installed: $($installed.Name)"
return $true
}
# Check via registry (more reliable for some apps)
$regPaths = @(
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*",
"HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*"
)
foreach ($path in $regPaths) {
$apps = Get-ItemProperty $path -ErrorAction SilentlyContinue | Where-Object { $_.DisplayName -like "*$AppName*" }
if ($apps) {
Write-Host " $AppName is already installed: $($apps[0].DisplayName)"
return $true
}
}
return $false
}
# Function to install via winget
function Install-ViaWinget {
param([string]$AppId, [string]$AppName)
Write-Host " Trying winget install $AppId"
try {
$result = & winget install $AppId --accept-package-agreements --accept-source-agreements --silent
if ($LASTEXITCODE -eq 0) {
Write-Host " [OK] $AppName installed via winget"
return $true
} else {
Write-Host " Winget install failed for $AppName"
return $false
}
} catch {
Write-Host " Winget not available or failed: $($_.Exception.Message)"
return $false
}
}
# Function to download and install manually
function Install-Manual {
param([string]$Url, [string]$FileName, [string]$Args, [string]$AppName)
Write-Host " Downloading $AppName from $Url"
$downloadPath = Join-Path $env:TEMP $FileName
try {
Invoke-WebRequest -Uri $Url -OutFile $downloadPath -UseBasicParsing
Write-Host " Downloaded to $downloadPath"
Write-Host " Installing $AppName..."
if ($Args) {
& $downloadPath $Args.Split(' ')
} else {
& $downloadPath
}
Start-Sleep -Seconds 3
# Clean up
Remove-Item $downloadPath -Force -ErrorAction SilentlyContinue
Write-Host " [OK] $AppName installation completed"
return $true
} catch {
Write-Host " [!] Manual install failed for $AppName: $($_.Exception.Message)"
return $false
}
}
Write-Host "[1/5] Installing AnyDesk"
if (-not (Test-AppInstalled -AppName "AnyDesk" -ProcessName "AnyDesk")) {
if (-not (Install-ViaWinget -AppId "AnyDeskSoftwareGmbH.AnyDesk" -AppName "AnyDesk")) {
Install-Manual -Url "https://download.anydesk.com/AnyDesk.exe" -FileName "AnyDesk.exe" -Args "--install --start-with-win --silent" -AppName "AnyDesk"
}
} else {
Write-Host " [SKIP] AnyDesk already installed"
}
Write-Host ""
Write-Host "[2/5] Installing LINE"
if (-not (Test-AppInstalled -AppName "LINE" -ProcessName "LINE")) {
if (-not (Install-ViaWinget -AppId "LINE.LINE" -AppName "LINE")) {
Install-Manual -Url "https://desktop.line-scdn.net/win/new/LineInst.exe" -FileName "LineInst.exe" -Args "/S" -AppName "LINE"
}
} else {
Write-Host " [SKIP] LINE already installed"
}
Write-Host ""
Write-Host "[3/5] Installing Google Chrome"
if (-not (Test-AppInstalled -AppName "Chrome" -ProcessName "chrome")) {
if (-not (Install-ViaWinget -AppId "Google.Chrome" -AppName "Chrome")) {
Install-Manual -Url "https://dl.google.com/chrome/install/GoogleChromeStandaloneEnterprise64.msi" -FileName "ChromeSetup.msi" -Args "/quiet /norestart" -AppName "Chrome"
}
} else {
Write-Host " [SKIP] Chrome already installed"
}
Write-Host ""
Write-Host "[4/5] Installing 7-Zip"
if (-not (Test-AppInstalled -AppName "7-Zip" -ProcessName "7zFM")) {
if (-not (Install-ViaWinget -AppId "7zip.7zip" -AppName "7-Zip")) {
Install-Manual -Url "https://7-zip.org/a/7z2301-x64.msi" -FileName "7zip-setup.msi" -Args "/quiet /norestart" -AppName "7-Zip"
}
} else {
Write-Host " [SKIP] 7-Zip already installed"
}
Write-Host ""
Write-Host "[5/5] Installing Adobe Reader"
if (-not (Test-AppInstalled -AppName "Adobe" -ProcessName "AcroRd32")) {
if (-not (Install-ViaWinget -AppId "Adobe.Acrobat.Reader.64-bit" -AppName "Adobe Reader")) {
# Adobe Reader requires more complex download, try alternative
Write-Host " [!] Adobe Reader requires manual download from Adobe website"
Write-Host " Please visit: https://get.adobe.com/reader/"
Write-Host " Or try: winget install Adobe.Acrobat.Reader.64-bit"
}
} else {
Write-Host " [SKIP] Adobe Reader already installed"
}
Write-Host ""
Write-Host "=== Installation Summary ==="
# Final verification
$apps = @(
@{Name="AnyDesk"; Process="AnyDesk"}
@{Name="LINE"; Process="LINE"}
@{Name="Chrome"; Process="chrome"}
@{Name="7-Zip"; Process="7zFM"}
@{Name="Adobe"; Process="AcroRd32"}
)
foreach ($app in $apps) {
$installed = Test-AppInstalled -AppName $app.Name -ProcessName $app.Process
if ($installed) {
Write-Host "[OK] $($app.Name) - Installed"
} else {
Write-Host "[!] $($app.Name) - Not detected (may need manual verification)"
}
}
Write-Host ""
Write-Host "[*] Application installation process completed"
Write-Host "Note: Some applications may require restart to appear in Start Menu"
Write-Host "All applications will be available to all users on this computer"

View File

@@ -0,0 +1,66 @@
[Console]::OutputEncoding = [Text.Encoding]::UTF8
$ErrorActionPreference = 'Stop'
$url = 'https://www.nirsoft.net/utils/cports-x64.zip'
$installDir = 'C:\Program Files\NirSoft\CurrPorts'
$exeName = 'cports.exe'
$exePath = Join-Path $installDir $exeName
# Idempotent
if (Test-Path $exePath) {
$ver = (Get-Item $exePath).VersionInfo.ProductVersion
Write-Host "[=] CurrPorts already installed: $exePath (v$ver)"
} else {
$tmpZip = Join-Path $env:TEMP 'cports-x64.zip'
$tmpDir = Join-Path $env:TEMP 'cports-extract'
if (Test-Path $tmpDir) { Remove-Item $tmpDir -Recurse -Force }
New-Item -ItemType Directory -Path $tmpDir | Out-Null
Write-Host "[*] Downloading $url"
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Invoke-WebRequest -Uri $url -OutFile $tmpZip -UseBasicParsing
if ((Get-Item $tmpZip).Length -lt 50KB) { throw "Downloaded zip too small" }
Expand-Archive -Path $tmpZip -DestinationPath $tmpDir -Force
if (-not (Test-Path (Join-Path $tmpDir $exeName))) {
throw "$exeName not found in archive"
}
New-Item -ItemType Directory -Force -Path $installDir | Out-Null
Copy-Item -Path (Join-Path $tmpDir '*') -Destination $installDir -Recurse -Force
Remove-Item $tmpZip -Force -ErrorAction SilentlyContinue
Remove-Item $tmpDir -Recurse -Force -ErrorAction SilentlyContinue
$ver = (Get-Item $exePath).VersionInfo.ProductVersion
Write-Host "[OK] Installed: $exePath (v$ver)"
}
# Start Menu shortcut for all users (Common Start Menu)
$commonStart = 'C:\ProgramData\Microsoft\Windows\Start Menu\Programs'
$lnkCommon = Join-Path $commonStart 'CurrPorts.lnk'
$wsh = New-Object -ComObject WScript.Shell
$lnk = $wsh.CreateShortcut($lnkCommon)
$lnk.TargetPath = $exePath
$lnk.WorkingDirectory = $installDir
$lnk.IconLocation = "$exePath,0"
$lnk.Description = 'NirSoft CurrPorts - list open TCP/UDP ports'
$lnk.Save()
Write-Host "[*] Start Menu (All Users) shortcut: $lnkCommon"
# Also desktop shortcut for the 'User' account (main daily-use account)
$userDesktop = 'C:\Users\user\Desktop'
if (Test-Path $userDesktop) {
$lnkUser = Join-Path $userDesktop 'CurrPorts.lnk'
$lnk2 = $wsh.CreateShortcut($lnkUser)
$lnk2.TargetPath = $exePath
$lnk2.WorkingDirectory = $installDir
$lnk2.IconLocation = "$exePath,0"
$lnk2.Save()
& icacls $lnkUser /grant 'User:F' /Q | Out-Null
Write-Host "[*] Desktop shortcut for User: $lnkUser"
}
Write-Host ""
Write-Host "Launch from Start menu, or run directly:"
Write-Host " `"$exePath`""

View File

@@ -0,0 +1,104 @@
[Console]::OutputEncoding = [Text.Encoding]::UTF8
$ErrorActionPreference = 'Continue'
Write-Host "[*] Installing essential applications"
Write-Host "Apps: AnyDesk, LINE, Chrome, 7zip, Adobe Reader"
Write-Host ""
# Install via winget (preferred method)
$apps = @(
@{Name="AnyDesk"; WingetId="AnyDeskSoftwareGmbH.AnyDesk"}
@{Name="LINE"; WingetId="LINE.LINE"}
@{Name="Google Chrome"; WingetId="Google.Chrome"}
@{Name="7-Zip"; WingetId="7zip.7zip"}
@{Name="Adobe Reader"; WingetId="Adobe.Acrobat.Reader.64-bit"}
)
$successCount = 0
$totalApps = $apps.Count
foreach ($app in $apps) {
Write-Host "Installing $($app.Name)..."
try {
$result = & winget install $app.WingetId --accept-package-agreements --accept-source-agreements --silent 2>&1
if ($LASTEXITCODE -eq 0) {
Write-Host " [OK] $($app.Name) installed successfully"
$successCount++
} else {
Write-Host " [SKIP] $($app.Name) may already be installed or failed"
# Check if already installed
$checkResult = & winget list $app.WingetId 2>&1
if ($LASTEXITCODE -eq 0) {
Write-Host " [INFO] $($app.Name) appears to be already installed"
$successCount++
}
}
} catch {
Write-Host " [ERROR] Failed to install $($app.Name)"
# Try alternative download for critical apps
if ($app.Name -eq "Google Chrome") {
Write-Host " Trying alternative Chrome download..."
try {
$chromeUrl = "https://dl.google.com/chrome/install/GoogleChromeStandaloneEnterprise64.msi"
$chromePath = "$env:TEMP\ChromeSetup.msi"
Invoke-WebRequest -Uri $chromeUrl -OutFile $chromePath -UseBasicParsing
& msiexec /i $chromePath /quiet /norestart
Write-Host " [OK] Chrome installed via direct download"
$successCount++
} catch {
Write-Host " [ERROR] Chrome alternative install failed"
}
}
}
Write-Host ""
}
Write-Host "=== Installation Summary ==="
Write-Host "Successfully installed: $successCount / $totalApps applications"
Write-Host ""
# Verify installations by checking common install locations
Write-Host "Verification:"
$verifyApps = @(
@{Name="AnyDesk"; Path="C:\Program Files (x86)\AnyDesk\AnyDesk.exe"}
@{Name="LINE"; Path="C:\Users\$env:USERNAME\AppData\Local\LINE\bin\LineLauncher.exe"}
@{Name="Chrome"; Path="C:\Program Files\Google\Chrome\Application\chrome.exe"}
@{Name="7-Zip"; Path="C:\Program Files\7-Zip\7z.exe"}
@{Name="Adobe Reader"; Path="C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe"}
)
foreach ($app in $verifyApps) {
if (Test-Path $app.Path) {
Write-Host " [OK] $($app.Name) - Found at expected location"
} else {
# Try to find in registry
$found = $false
$regPaths = @(
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*",
"HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*"
)
foreach ($regPath in $regPaths) {
$installed = Get-ItemProperty $regPath -ErrorAction SilentlyContinue |
Where-Object { $_.DisplayName -like "*$($app.Name.Split(' ')[0])*" }
if ($installed) {
Write-Host " [OK] $($app.Name) - Found in registry"
$found = $true
break
}
}
if (-not $found) {
Write-Host " [!] $($app.Name) - Not detected"
}
}
}
Write-Host ""
Write-Host "Installation completed!"
Write-Host "Note: Applications may require restart to appear in Start Menu"

View File

@@ -0,0 +1,102 @@
[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"

View File

@@ -0,0 +1,187 @@
[Console]::OutputEncoding = [Text.Encoding]::UTF8
$ErrorActionPreference = 'Continue'
Write-Host "[*] Installing remaining applications with Windows Defender bypass"
Write-Host "Apps: AnyDesk, LINE, Adobe Reader"
Write-Host ""
# Check if running as administrator
$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not $isAdmin) {
Write-Host "[!] ERROR: This script must be run as Administrator"
exit 1
}
$downloadFolder = "$env:TEMP\DirectAppInstalls"
New-Item -ItemType Directory -Force -Path $downloadFolder | Out-Null
# Function to temporarily disable Windows Defender
function Disable-WindowsDefender {
Write-Host "[*] Temporarily disabling Windows Defender real-time protection..."
try {
Set-MpPreference -DisableRealtimeMonitoring $true
Write-Host " [OK] Windows Defender real-time protection disabled"
return $true
} catch {
Write-Host " [!] Failed to disable Windows Defender: $($_.Exception.Message)"
Write-Host " Continuing with installation anyway..."
return $false
}
}
# Function to re-enable Windows Defender
function Enable-WindowsDefender {
Write-Host "[*] Re-enabling Windows Defender real-time protection..."
try {
Set-MpPreference -DisableRealtimeMonitoring $false
Write-Host " [OK] Windows Defender real-time protection re-enabled"
} catch {
Write-Host " [!] Failed to re-enable Windows Defender: $($_.Exception.Message)"
}
}
# Function to install application
function Install-DirectApp {
param(
[string]$Name,
[string]$Url,
[string]$FileName,
[string]$InstallArgs,
[int]$TimeoutMinutes = 5
)
Write-Host "Installing $Name..."
Write-Host " URL: $Url"
$downloadPath = Join-Path $downloadFolder $FileName
$success = $false
try {
# Download
Write-Host " Downloading..."
Invoke-WebRequest -Uri $Url -OutFile $downloadPath -UseBasicParsing -TimeoutSec 120
if (Test-Path $downloadPath) {
$fileSize = (Get-Item $downloadPath).Length / 1MB
Write-Host " Downloaded: $([math]::Round($fileSize, 2)) MB"
# Install
Write-Host " Installing with args: $InstallArgs"
if ($FileName.EndsWith(".msi")) {
$process = Start-Process -FilePath "msiexec" -ArgumentList "/i", $downloadPath, $InstallArgs -Wait -PassThru
} else {
$argList = $InstallArgs.Split(' ') + $downloadPath
$process = Start-Process -FilePath $downloadPath -ArgumentList $InstallArgs -Wait -PassThru -WindowStyle Hidden
}
Write-Host " Process exit code: $($process.ExitCode)"
if ($process.ExitCode -eq 0 -or $process.ExitCode -eq 3010) {
Write-Host " [OK] $Name installation completed successfully"
$success = $true
} else {
Write-Host " [!] $Name installation may have failed (exit code: $($process.ExitCode))"
# Some installers return non-zero codes even on success, so we'll verify later
}
} else {
Write-Host " [!] Download failed - file not found"
}
} catch {
Write-Host " [ERROR] $Name installation failed: $($_.Exception.Message)"
} finally {
# Clean up download
if (Test-Path $downloadPath) {
Remove-Item $downloadPath -Force -ErrorAction SilentlyContinue
}
}
return $success
}
# Applications to install
$apps = @(
@{
Name = "AnyDesk"
Url = "https://download.anydesk.com/AnyDesk.msi"
FileName = "AnyDesk.msi"
InstallArgs = "/quiet /norestart"
},
@{
Name = "LINE"
Url = "https://desktop.line-scdn.net/win/new/LineInst.exe"
FileName = "LineInst.exe"
InstallArgs = "/S"
},
@{
Name = "Adobe Reader"
Url = "https://ardownload2.adobe.com/pub/adobe/reader/win/AcrobatDC/2300820555/AcroRdrDC2300820555_en_US.exe"
FileName = "AdobeReader.exe"
InstallArgs = "/sAll /rs /msi EULA_ACCEPT=YES"
}
)
Write-Host "=== Starting Installation Process ==="
Write-Host ""
# Disable Windows Defender
$defenderDisabled = Disable-WindowsDefender
$installedCount = 0
$totalApps = $apps.Count
try {
foreach ($app in $apps) {
Write-Host "[$($installedCount + 1)/$totalApps] $($app.Name)"
if (Install-DirectApp -Name $app.Name -Url $app.Url -FileName $app.FileName -InstallArgs $app.InstallArgs) {
$installedCount++
}
Write-Host ""
Start-Sleep -Seconds 3
}
} finally {
# Always re-enable Windows Defender
if ($defenderDisabled) {
Enable-WindowsDefender
}
}
# Clean up download folder
Remove-Item $downloadFolder -Recurse -Force -ErrorAction SilentlyContinue
Write-Host "=== Installation Summary ==="
Write-Host "Successfully installed: $installedCount / $totalApps applications"
Write-Host ""
# Final verification
Write-Host "=== Verification ==="
$verificationPaths = @(
@{Name="AnyDesk"; Paths=@("C:\Program Files (x86)\AnyDesk\AnyDesk.exe", "C:\Program Files\AnyDesk\AnyDesk.exe")},
@{Name="LINE"; Paths=@("C:\Users\$env:USERNAME\AppData\Local\LINE\bin\LineLauncher.exe", "C:\Program Files\LINE\bin\LineLauncher.exe")},
@{Name="Adobe Reader"; Paths=@("C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe", "C:\Program Files\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe")}
)
foreach ($check in $verificationPaths) {
$found = $false
foreach ($path in $check.Paths) {
if (Test-Path $path) {
Write-Host "[OK] $($check.Name) - Found at $path"
$found = $true
break
}
}
if (-not $found) {
Write-Host "[!] $($check.Name) - Not found (may need restart or manual verification)"
}
}
Write-Host ""
Write-Host "Installation completed!"
Write-Host "Note: Some applications may require restart to appear in Start Menu"
Write-Host "Windows Defender real-time protection has been restored"

View File

@@ -0,0 +1,102 @@
param(
[string]$TargetUser = 'user'
)
[Console]::OutputEncoding = [Text.Encoding]::UTF8
$ErrorActionPreference = 'Stop'
$targetProfile = "C:\Users\$TargetUser"
if (-not (Test-Path $targetProfile)) { throw "Windows user '$TargetUser' not found ($targetProfile missing)" }
$installDir = Join-Path $targetProfile 'AppData\Roaming\Telegram Desktop'
$startMenuDir = Join-Path $targetProfile 'AppData\Roaming\Microsoft\Windows\Start Menu\Programs'
$desktopDir = Join-Path $targetProfile 'Desktop'
function Get-TelegramVersion($dir) {
$exe = Join-Path $dir 'Telegram.exe'
if (Test-Path $exe) { return (Get-Item $exe).VersionInfo.ProductVersion }
return $null
}
# Already installed at target?
$existingVer = Get-TelegramVersion $installDir
if ($existingVer) {
Write-Host "[=] Already installed for '$TargetUser': Telegram $existingVer at $installDir"
exit 0
}
# Clean up any stray Admin-scoped install that we may have created earlier
$adminDir = 'C:\Users\Admin\AppData\Roaming\Telegram Desktop'
$adminUninst = Join-Path $adminDir 'unins000.exe'
if ((Test-Path $adminUninst) -and ($TargetUser -ne 'Admin')) {
Write-Host "[*] Removing stray Admin-scoped install at $adminDir"
Get-Process Telegram,Updater -ErrorAction SilentlyContinue | Stop-Process -Force
$p = Start-Process -FilePath $adminUninst -ArgumentList '/VERYSILENT','/SUPPRESSMSGBOXES','/NORESTART' -Wait -PassThru
if ($p.ExitCode -ne 0) { Write-Host "[!] Uninstall exited $($p.ExitCode), continuing anyway" }
# Remove Admin's HKCU uninstall key (best-effort)
Get-Item 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*' -ErrorAction SilentlyContinue |
Where-Object { (Get-ItemProperty $_.PSPath).DisplayName -match 'Telegram' } |
ForEach-Object { Remove-Item $_.PSPath -Force -Recurse -ErrorAction SilentlyContinue }
# Remove Admin's start menu shortcut
$adminLnk = 'C:\Users\Admin\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Telegram.lnk'
Remove-Item $adminLnk -ErrorAction SilentlyContinue
Start-Sleep -Seconds 2
}
# Download installer
$url = 'https://telegram.org/dl/desktop/win64'
$dst = Join-Path $env:TEMP 'telegram-setup.exe'
Write-Host "[*] Downloading installer -> $dst"
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Invoke-WebRequest -Uri $url -OutFile $dst -UseBasicParsing
if (-not (Test-Path $dst) -or (Get-Item $dst).Length -lt 10MB) {
throw "Downloaded file looks wrong (< 10 MB)"
}
# Install into target user's AppData. /NOICONS = no shortcuts (we'll create them in target's profile).
New-Item -ItemType Directory -Force -Path $installDir | Out-Null
$argStr = '/VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP- /NOICONS /NOLAUNCH /DIR="' + $installDir + '"'
Write-Host "[*] Installing to $installDir"
$p = Start-Process -FilePath $dst -ArgumentList $argStr -Wait -PassThru
Remove-Item $dst -ErrorAction SilentlyContinue
if ($p.ExitCode -ne 0) { throw "Installer exited $($p.ExitCode)" }
# Verify binary appeared
$finalVer = Get-TelegramVersion $installDir
if (-not $finalVer) { throw "Telegram.exe not found at $installDir after install" }
# Give target user full control over the install tree
Write-Host "[*] Adjusting ACL on $installDir for '$TargetUser'"
& icacls $installDir /grant "${TargetUser}:(OI)(CI)F" /T /Q | Out-Null
# Create Start Menu shortcut in target user's profile
New-Item -ItemType Directory -Force -Path $startMenuDir | Out-Null
$wsh = New-Object -ComObject WScript.Shell
$lnk = $wsh.CreateShortcut((Join-Path $startMenuDir 'Telegram.lnk'))
$lnk.TargetPath = Join-Path $installDir 'Telegram.exe'
$lnk.WorkingDirectory = $installDir
$lnk.IconLocation = (Join-Path $installDir 'Telegram.exe') + ',0'
$lnk.Save()
Write-Host "[*] Start menu shortcut: $(Join-Path $startMenuDir 'Telegram.lnk')"
# Desktop shortcut
if (Test-Path $desktopDir) {
$dlnk = $wsh.CreateShortcut((Join-Path $desktopDir 'Telegram.lnk'))
$dlnk.TargetPath = Join-Path $installDir 'Telegram.exe'
$dlnk.WorkingDirectory = $installDir
$dlnk.IconLocation = (Join-Path $installDir 'Telegram.exe') + ',0'
$dlnk.Save()
Write-Host "[*] Desktop shortcut: $(Join-Path $desktopDir 'Telegram.lnk')"
}
# Fix ACL on the shortcuts too
& icacls (Join-Path $startMenuDir 'Telegram.lnk') /grant "${TargetUser}:F" /Q | Out-Null
if (Test-Path (Join-Path $desktopDir 'Telegram.lnk')) {
& icacls (Join-Path $desktopDir 'Telegram.lnk') /grant "${TargetUser}:F" /Q | Out-Null
}
Write-Host ""
Write-Host "[OK] Telegram $finalVer installed for '$TargetUser'"
Write-Host " Location: $installDir"
Write-Host " Data (tdata) will be created beside the exe on first launch."

View File

@@ -0,0 +1,73 @@
[Console]::OutputEncoding = [Text.Encoding]::UTF8
$ErrorActionPreference = 'Stop'
function Test-Installed {
$keys = @(
'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*',
'HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
)
Get-ItemProperty $keys -ErrorAction SilentlyContinue |
Where-Object { $_.DisplayName -match 'Thunderbird' } |
Select-Object -First 1 DisplayName,DisplayVersion,InstallLocation
}
$existing = Test-Installed
if ($existing) {
Write-Host "[=] Thunderbird already installed: $($existing.DisplayName) $($existing.DisplayVersion)"
Write-Host " Location: $($existing.InstallLocation)"
exit 0
}
$installed = $false
# --- Attempt 1: winget ---
$winget = Get-Command winget -ErrorAction SilentlyContinue
if ($winget) {
Write-Host "[*] winget found, installing Mozilla.Thunderbird"
try {
& winget install --id Mozilla.Thunderbird -e --silent `
--accept-source-agreements --accept-package-agreements `
--scope machine 2>&1 | Write-Host
if ($LASTEXITCODE -eq 0) { $installed = $true }
else { Write-Host "[!] winget exited $LASTEXITCODE, falling back to direct download" }
} catch {
Write-Host "[!] winget failed: $_"
}
} else {
Write-Host "[!] winget not available, using direct download"
}
# --- Attempt 2: direct download from Mozilla CDN ---
if (-not $installed) {
$url = 'https://download.mozilla.org/?product=thunderbird-latest&os=win64&lang=zh-TW'
$dst = Join-Path $env:TEMP 'thunderbird-setup.exe'
Write-Host "[*] Downloading installer -> $dst"
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Invoke-WebRequest -Uri $url -OutFile $dst -UseBasicParsing
if (-not (Test-Path $dst) -or (Get-Item $dst).Length -lt 10MB) {
throw "Downloaded file looks wrong (size < 10 MB)"
}
Write-Host "[*] Running silent install"
$proc = Start-Process -FilePath $dst -ArgumentList '/S' -Wait -PassThru
if ($proc.ExitCode -ne 0) {
throw "Installer exited with code $($proc.ExitCode)"
}
Remove-Item $dst -ErrorAction SilentlyContinue
$installed = $true
}
# --- Verify ---
Start-Sleep -Seconds 2
$after = Test-Installed
if ($after) {
Write-Host ""
Write-Host "[OK] Installed: $($after.DisplayName) $($after.DisplayVersion)"
Write-Host " Location: $($after.InstallLocation)"
exit 0
} else {
Write-Host "[FAIL] Thunderbird was not detected in uninstall registry after install"
exit 1
}

View File

@@ -0,0 +1,135 @@
[Console]::OutputEncoding = [Text.Encoding]::UTF8
$ErrorActionPreference = 'Continue'
Write-Host "[*] Investigating application installation failures"
Write-Host ""
# Error code analysis
Write-Host "=== Error Code Analysis ==="
Write-Host "Error code -1978335212 (0x8A150054) typically indicates:"
Write-Host "- APPINSTALLER_CLI_ERROR_INSTALLER_FAILED"
Write-Host "- The package installer failed during execution"
Write-Host ""
Write-Host "[1] Checking system requirements and dependencies..."
# Check Windows version
$osInfo = Get-ComputerInfo | Select-Object WindowsProductName, WindowsVersion, WindowsBuildLabEx
Write-Host "OS: $($osInfo.WindowsProductName)"
Write-Host "Version: $($osInfo.WindowsVersion)"
Write-Host "Build: $($osInfo.WindowsBuildLabEx)"
# Check available disk space
$disk = Get-WmiObject -Class Win32_LogicalDisk | Where-Object {$_.DeviceID -eq "C:"}
$freeSpaceGB = [math]::Round($disk.FreeSpace / 1GB, 2)
Write-Host "Free space on C: drive: $freeSpaceGB GB"
Write-Host ""
Write-Host "[2] Checking for conflicting installations..."
# Check if any versions are already partially installed
$installedApps = Get-WmiObject -Class Win32_Product | Where-Object {
$_.Name -like "*AnyDesk*" -or
$_.Name -like "*LINE*" -or
$_.Name -like "*Adobe*Reader*"
} | Select-Object Name, Version, IdentifyingNumber
if ($installedApps) {
Write-Host "Found existing installations:"
foreach ($app in $installedApps) {
Write-Host " - $($app.Name) v$($app.Version)"
}
} else {
Write-Host "No conflicting installations found"
}
Write-Host ""
Write-Host "[3] Testing individual app availability..."
$failedApps = @(
@{Name="AnyDesk"; Id="AnyDeskSoftwareGmbH.AnyDesk"},
@{Name="LINE"; Id="LINE.LINE"},
@{Name="Adobe Reader"; Id="Adobe.Acrobat.Reader.64-bit"}
)
foreach ($app in $failedApps) {
Write-Host "Testing $($app.Name)..."
# Check if app is available in winget
try {
$searchResult = & winget show $app.Id --source winget 2>&1
if ($LASTEXITCODE -eq 0) {
Write-Host " [OK] Package found in winget"
# Extract some key info
$lines = $searchResult -split "`n"
foreach ($line in $lines) {
if ($line -like "*Version:*" -or $line -like "*Publisher:*" -or $line -like "*Package Url:*") {
Write-Host " $line"
}
}
} else {
Write-Host " [!] Package not found or access denied"
}
} catch {
Write-Host " [!] Search failed: $($_.Exception.Message)"
}
Write-Host ""
}
Write-Host "[4] Checking system policies and restrictions..."
# Check execution policy
$execPolicy = Get-ExecutionPolicy -Scope LocalMachine
Write-Host "Execution Policy: $execPolicy"
# Check if running as administrator
$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
Write-Host "Running as Administrator: $isAdmin"
# Check Windows Defender status
try {
$defender = Get-MpPreference -ErrorAction SilentlyContinue
if ($defender) {
Write-Host "Windows Defender Real-time Protection: $($defender.DisableRealtimeMonitoring -eq $false)"
}
} catch {
Write-Host "Cannot check Windows Defender status"
}
Write-Host ""
Write-Host "[5] Testing direct download availability..."
$downloadTests = @(
@{Name="AnyDesk"; Url="https://download.anydesk.com/AnyDesk.exe"},
@{Name="LINE"; Url="https://desktop.line-scdn.net/win/new/LineInst.exe"},
@{Name="Adobe Reader"; Url="https://ardownload2.adobe.com/pub/adobe/reader/win/AcrobatDC/2300820555/AcroRdrDC2300820555_en_US.exe"}
)
foreach ($test in $downloadTests) {
Write-Host "Testing $($test.Name) direct download..."
try {
$webRequest = Invoke-WebRequest -Uri $test.Url -Method Head -UseBasicParsing -TimeoutSec 10
Write-Host " [OK] Direct download available (Status: $($webRequest.StatusCode))"
} catch {
Write-Host " [!] Direct download failed: $($_.Exception.Message)"
}
}
Write-Host ""
Write-Host "=== Investigation Summary ==="
Write-Host ""
Write-Host "Possible reasons for failures:"
Write-Host "1. Package installer requirements not met (missing dependencies)"
Write-Host "2. Antivirus/Windows Defender blocking installation"
Write-Host "3. Insufficient permissions despite administrator status"
Write-Host "4. Network connectivity issues to specific download servers"
Write-Host "5. Package conflicts with existing system components"
Write-Host "6. Windows version compatibility issues"
Write-Host ""
Write-Host "Recommended solutions:"
Write-Host "1. Try direct installer downloads with elevated permissions"
Write-Host "2. Temporarily disable real-time protection during installation"
Write-Host "3. Use alternative installation sources or older versions"
Write-Host "4. Install dependencies manually before main applications"

View File

@@ -0,0 +1,145 @@
[Console]::OutputEncoding = [Text.Encoding]::UTF8
$ErrorActionPreference = 'Continue'
Write-Host "[*] Mapping R: drive with anonymous access (no credentials)"
$networkPath = "\\192.168.88.231\RD"
$driveLetter = "R:"
# First, remove any existing R: mapping
Write-Host "[*] Cleaning up existing mappings"
try {
& net use $driveLetter /delete /yes 2>$null
Write-Host " Cleared any existing R: mapping"
} catch {
Write-Host " No existing mapping to clear"
}
Write-Host "[*] Testing anonymous access methods"
# Method 1: Simple net use without credentials
Write-Host "[1] Trying simple net use..."
try {
$result = & net use $driveLetter $networkPath /persistent:yes
if ($LASTEXITCODE -eq 0) {
Write-Host "[OK] Method 1 successful!"
$success = $true
} else {
Write-Host " Method 1 failed: $result"
$success = $false
}
} catch {
Write-Host " Method 1 exception: $($_.Exception.Message)"
$success = $false
}
# Method 2: Explicit guest access
if (-not $success) {
Write-Host "[2] Trying guest access..."
try {
$result = & net use $driveLetter $networkPath /user:guest "" /persistent:yes
if ($LASTEXITCODE -eq 0) {
Write-Host "[OK] Method 2 successful!"
$success = $true
} else {
Write-Host " Method 2 failed: $result"
}
} catch {
Write-Host " Method 2 exception: $($_.Exception.Message)"
}
}
# Method 3: Empty username
if (-not $success) {
Write-Host "[3] Trying empty username..."
try {
$result = & net use $driveLetter $networkPath /user:"" "" /persistent:yes
if ($LASTEXITCODE -eq 0) {
Write-Host "[OK] Method 3 successful!"
$success = $true
} else {
Write-Host " Method 3 failed: $result"
}
} catch {
Write-Host " Method 3 exception: $($_.Exception.Message)"
}
}
# Method 4: Using PowerShell New-PSDrive
if (-not $success) {
Write-Host "[4] Trying PowerShell PSDrive..."
try {
New-PSDrive -Name "R" -PSProvider FileSystem -Root $networkPath -Persist -ErrorAction Stop
Write-Host "[OK] Method 4 successful!"
$success = $true
} catch {
Write-Host " Method 4 exception: $($_.Exception.Message)"
}
}
# Verify the mapping
Write-Host "[*] Verifying drive mapping"
Start-Sleep -Seconds 2
$driveCheck = Get-WmiObject -Class Win32_LogicalDisk | Where-Object { $_.DeviceID -eq $driveLetter }
if ($driveCheck -and $driveCheck.DriveType -eq 4) {
Write-Host "[OK] Network drive R: successfully mapped!"
Write-Host " Device: $($driveCheck.DeviceID)"
Write-Host " Provider: $($driveCheck.ProviderName)"
Write-Host " Type: Network Drive"
# Test accessibility
try {
if (Test-Path "${driveLetter}\") {
Write-Host "[OK] Drive R: is accessible"
# List contents
$items = Get-ChildItem "${driveLetter}\" -ErrorAction SilentlyContinue
if ($items) {
Write-Host " Contents: $($items.Count) items found"
Write-Host " Sample items:"
$items | Select-Object -First 3 | ForEach-Object {
Write-Host " - $($_.Name) ($($_.Mode))"
}
} else {
Write-Host " Directory appears empty"
}
} else {
Write-Host "[!] Drive mapped but not accessible"
}
} catch {
Write-Host "[!] Error testing accessibility: $($_.Exception.Message)"
}
} else {
Write-Host "[!] Drive mapping verification failed"
# Show current network drives
$networkDrives = Get-WmiObject -Class Win32_LogicalDisk | Where-Object { $_.DriveType -eq 4 }
if ($networkDrives) {
Write-Host "Current network drives:"
foreach ($drive in $networkDrives) {
Write-Host " $($drive.DeviceID) -> $($drive.ProviderName)"
}
} else {
Write-Host "No network drives currently mapped"
}
Write-Host ""
Write-Host "Manual verification:"
Write-Host "1. Open File Explorer"
Write-Host "2. Check if R: drive appears under 'This PC'"
Write-Host "3. Try accessing \\192.168.88.231\RD directly"
}
Write-Host ""
Write-Host "[*] Drive mapping process completed"
# Clean up the desktop batch file since we don't need credentials
$batchFile = "C:\Users\User\Desktop\Map-Drive-R.bat"
if (Test-Path $batchFile) {
Remove-Item $batchFile -Force -ErrorAction SilentlyContinue
Write-Host " Removed credential batch file (not needed)"
}

View File

@@ -0,0 +1,98 @@
[Console]::OutputEncoding = [Text.Encoding]::UTF8
$ErrorActionPreference = 'Continue'
Write-Host "[*] Mapping network drive R: with persistent connection"
$networkPath = "\\192.168.88.231\RD"
$driveLetter = "R:"
Write-Host "[*] Creating persistent network drive mapping"
Write-Host " Target: $networkPath"
Write-Host " Drive: $driveLetter"
# Method 1: Try mapping without credentials first (anonymous/guest access)
Write-Host "[*] Attempting anonymous mapping..."
try {
$result = & net use $driveLetter $networkPath /persistent:yes 2>&1
if ($LASTEXITCODE -eq 0) {
Write-Host "[OK] Anonymous mapping successful!"
} else {
Write-Host " Anonymous mapping failed, will require manual credentials"
}
} catch {
Write-Host " Exception during anonymous mapping"
}
# Check if mapping was successful
$driveCheck = Get-WmiObject -Class Win32_LogicalDisk | Where-Object { $_.DeviceID -eq $driveLetter }
if ($driveCheck -and $driveCheck.DriveType -eq 4) {
Write-Host "[OK] Network drive R: successfully mapped!"
Write-Host " Provider: $($driveCheck.ProviderName)"
# Test access
try {
$testAccess = Test-Path "${driveLetter}\"
if ($testAccess) {
Write-Host "[OK] Drive R: is accessible"
# Try to list contents
$items = Get-ChildItem "${driveLetter}\" -ErrorAction SilentlyContinue | Select-Object -First 3
if ($items) {
Write-Host " Found $($items.Count) items in the drive"
} else {
Write-Host " Drive appears empty or no read permission"
}
} else {
Write-Host "[!] Drive R: mapped but not accessible"
}
} catch {
Write-Host "[!] Cannot test drive access: $($_.Exception.Message)"
}
} else {
Write-Host "[!] Network drive mapping incomplete"
Write-Host ""
Write-Host "Manual mapping required:"
Write-Host "1. Open File Explorer"
Write-Host "2. Right-click 'This PC' > Map network drive"
Write-Host "3. Drive: R:"
Write-Host "4. Folder: \\192.168.88.231\RD"
Write-Host "5. Check 'Reconnect at sign-in'"
Write-Host "6. Enter credentials when prompted"
Write-Host ""
Write-Host "Or use command line:"
Write-Host "net use R: \\192.168.88.231\RD /user:username /persistent:yes"
}
# Create a batch file for easy manual mapping
$batchContent = @"
@echo off
echo Mapping network drive R: to \\192.168.88.231\RD
echo.
echo If prompted, enter the username and password for 192.168.88.231
echo.
net use R: \\192.168.88.231\RD /persistent:yes
echo.
if %errorlevel%==0 (
echo Success! Drive R: mapped successfully.
explorer R:\
) else (
echo Mapping failed. Please check credentials and network connectivity.
)
pause
"@
$batchPath = "C:\Users\User\Desktop\Map-Drive-R.bat"
$batchContent | Out-File -FilePath $batchPath -Encoding ASCII
Write-Host "[*] Created manual mapping batch file: Map-Drive-R.bat"
Write-Host ""
Write-Host "Network drive setup complete!"
Write-Host ""
Write-Host "If R: drive is not visible:"
Write-Host "1. Double-click 'Map-Drive-R.bat' on User's desktop"
Write-Host "2. Enter network credentials when prompted"
Write-Host "3. Drive R: will appear in File Explorer"

View File

@@ -0,0 +1,96 @@
[Console]::OutputEncoding = [Text.Encoding]::UTF8
$ErrorActionPreference = 'Continue'
$ns = 'C:\Program Files\NirSoft'
$stamp = Get-Date -Format 'yyyyMMdd-HHmmss'
$hostname = $env:COMPUTERNAME
$outDir = Join-Path $env:TEMP "nirsoft-dump-$hostname-$stamp"
New-Item -ItemType Directory -Force -Path $outDir | Out-Null
function Run-Tool {
param(
[string]$Name,
[string]$Exe,
[string[]]$ArgList,
[int]$TimeoutSec = 60
)
$path = Join-Path $ns "$Name\$Exe"
if (-not (Test-Path $path)) {
Write-Host "[skip] $Name not installed"
return
}
Write-Host "[*] $Name"
try {
$p = Start-Process -FilePath $path -ArgumentList $ArgList -Wait -PassThru -WindowStyle Hidden
if ($p.ExitCode -ne 0) { Write-Host " (exit $($p.ExitCode))" }
} catch {
Write-Host " [!] $($_.Exception.Message)"
}
}
# === NirSoft CSV dumps ===
Run-Tool 'BlueScreenView' 'BlueScreenView.exe' @('/scomma', (Join-Path $outDir 'bluescreen.csv'))
Run-Tool 'LastActivityView' 'LastActivityView.exe' @('/scomma', (Join-Path $outDir 'lastactivity.csv'))
Run-Tool 'WhatInStartup' 'WhatInStartup.exe' @('/scomma', (Join-Path $outDir 'startup.csv'))
Run-Tool 'OpenedFilesView' 'OpenedFilesView.exe' @('/scomma', (Join-Path $outDir 'opened-files.csv'))
Run-Tool 'InstalledAppView' 'InstalledAppView.exe' @('/scomma', (Join-Path $outDir 'installed-apps.csv'))
Run-Tool 'DevManView' 'DevManView.exe' @('/scomma', (Join-Path $outDir 'devices.csv'))
Run-Tool 'USBDeview' 'USBDeview.exe' @('/scomma', (Join-Path $outDir 'usb-history.csv'))
Run-Tool 'TurnedOnTimesView' 'TurnedOnTimesView.exe' @('/scomma', (Join-Path $outDir 'uptime.csv'))
Run-Tool 'CurrPorts' 'cports.exe' @('/scomma', (Join-Path $outDir 'ports.csv'))
Run-Tool 'WifiInfoView' 'WifiInfoView.exe' @('/scomma', (Join-Path $outDir 'wifi-nearby.csv'))
Run-Tool 'WirelessNetView' 'WirelessNetView.exe' @('/scomma', (Join-Path $outDir 'wifi-tracking.csv'))
Run-Tool 'DNSDataView' 'DNSDataView.exe' @('/scomma', (Join-Path $outDir 'dns-cache.csv'))
# === Native Windows snapshots ===
Write-Host ""
Write-Host "[*] Native Windows snapshots"
& systeminfo.exe | Out-File (Join-Path $outDir 'systeminfo.txt') -Encoding UTF8
& ipconfig.exe /all | Out-File (Join-Path $outDir 'ipconfig.txt') -Encoding UTF8
& netstat.exe -ano | Out-File (Join-Path $outDir 'netstat.txt') -Encoding UTF8
Get-Process | Select-Object Id,ProcessName,CPU,WS,@{n='WS_MB';e={[math]::Round($_.WS/1MB,1)}},Path,StartTime |
Export-Csv -Path (Join-Path $outDir 'processes.csv') -NoTypeInformation -Encoding UTF8
Get-Service | Select-Object Name,DisplayName,Status,StartType |
Export-Csv -Path (Join-Path $outDir 'services.csv') -NoTypeInformation -Encoding UTF8
Get-ScheduledTask | Select-Object TaskPath,TaskName,State,Author |
Export-Csv -Path (Join-Path $outDir 'scheduled-tasks.csv') -NoTypeInformation -Encoding UTF8
# Recent error/warning events (System + Application, last 24h)
Get-WinEvent -FilterHashtable @{LogName='System'; Level=1,2,3; StartTime=(Get-Date).AddHours(-24)} -MaxEvents 500 -ErrorAction SilentlyContinue |
Select-Object TimeCreated,Id,LevelDisplayName,ProviderName,Message |
Export-Csv -Path (Join-Path $outDir 'events-system-24h.csv') -NoTypeInformation -Encoding UTF8
Get-WinEvent -FilterHashtable @{LogName='Application'; Level=1,2,3; StartTime=(Get-Date).AddHours(-24)} -MaxEvents 500 -ErrorAction SilentlyContinue |
Select-Object TimeCreated,Id,LevelDisplayName,ProviderName,Message |
Export-Csv -Path (Join-Path $outDir 'events-application-24h.csv') -NoTypeInformation -Encoding UTF8
# === Summary file ===
@"
=== Nirsoft + System Dump ===
Host: $hostname
Timestamp: $stamp
User running: $env:USERDOMAIN\$env:USERNAME
OS: $((Get-CimInstance Win32_OperatingSystem).Caption) $((Get-CimInstance Win32_OperatingSystem).Version)
Boot time: $((Get-CimInstance Win32_OperatingSystem).LastBootUpTime)
Uptime: $((Get-Date) - (Get-CimInstance Win32_OperatingSystem).LastBootUpTime)
Files in this archive:
$((Get-ChildItem $outDir | Sort-Object Name | ForEach-Object { " - $($_.Name) ($(if ($_.Length) { '{0:N0}' -f $_.Length } else { '-' }) bytes)" }) -join "`r`n")
"@ | Out-File (Join-Path $outDir '_summary.txt') -Encoding UTF8
# === Zip and announce ===
$zipPath = "$outDir.zip"
Compress-Archive -Path (Join-Path $outDir '*') -DestinationPath $zipPath -Force
$zipSize = (Get-Item $zipPath).Length
Write-Host ""
Write-Host "====================================="
Write-Host "DUMP_ZIP: $zipPath"
Write-Host "DUMP_SIZE: $zipSize"
Write-Host "====================================="
# Optional cleanup of the uncompressed dir
Remove-Item $outDir -Recurse -Force -ErrorAction SilentlyContinue

View File

@@ -0,0 +1,72 @@
[Console]::OutputEncoding = [Text.Encoding]::UTF8
$ErrorActionPreference = 'Continue'
Write-Host "[*] Pin RDP connection to taskbar"
# File paths
$rdpFile = "C:\Users\User\Desktop\Remote-Desktop.rdp"
$shortcutPath = "C:\Users\User\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Remote Desktop.lnk"
# Check if RDP file exists
if (-not (Test-Path $rdpFile)) {
Write-Host "[!] RDP file not found: $rdpFile"
exit 1
}
Write-Host "[*] Creating Start Menu shortcut"
# Create WScript.Shell object
$WshShell = New-Object -comObject WScript.Shell
# Create shortcut
$Shortcut = $WshShell.CreateShortcut($shortcutPath)
$Shortcut.TargetPath = "mstsc.exe"
$Shortcut.Arguments = "`"$rdpFile`""
$Shortcut.WorkingDirectory = "C:\Windows\System32"
$Shortcut.IconLocation = "mstsc.exe,0"
$Shortcut.Description = "Remote Desktop Connection"
$Shortcut.WindowStyle = 1
$Shortcut.Save()
Write-Host " Shortcut created: $shortcutPath"
# Pin to taskbar method
Write-Host "[*] Attempting to pin to taskbar"
try {
# Method 1: Try using verb
$shell = New-Object -ComObject Shell.Application
$folder = $shell.Namespace((Split-Path $shortcutPath))
$item = $folder.ParseName((Split-Path $shortcutPath -Leaf))
$verbs = $item.Verbs()
$pinVerb = $verbs | Where-Object { $_.Name -match "Pin to taskbar|taskbar" }
if ($pinVerb) {
Write-Host " Found pin verb: $($pinVerb.Name)"
$pinVerb.DoIt()
Write-Host "[OK] Successfully pinned to taskbar"
} else {
Write-Host "[!] Pin to taskbar verb not found"
Write-Host "Manual steps:"
Write-Host "1. Open Start Menu"
Write-Host "2. Find 'Remote Desktop' shortcut"
Write-Host "3. Right-click > Pin to taskbar"
}
} catch {
Write-Host "[!] Auto-pin failed: $($_.Exception.Message)"
Write-Host "Please pin manually from Start Menu"
}
# Optionally remove desktop RDP file
Write-Host "[*] Cleaning up desktop RDP file"
try {
Remove-Item $rdpFile -Force
Write-Host " Desktop RDP file removed"
} catch {
Write-Host " Desktop RDP file kept"
}
Write-Host ""
Write-Host "[OK] Setup complete! Check Start Menu for Remote Desktop shortcut"

View File

@@ -0,0 +1,91 @@
[Console]::OutputEncoding = [Text.Encoding]::UTF8
$ErrorActionPreference = 'SilentlyContinue'
function Section($title) {
Write-Host ''
Write-Host ('=' * 6) $title ('=' * 6) -ForegroundColor Cyan
}
Section 'Computer'
Get-ComputerInfo -Property CsName,CsDomain,CsManufacturer,CsModel,
WindowsProductName,OsVersion,OsBuildNumber,OsArchitecture,OsInstallDate,
CsNumberOfProcessors,CsNumberOfLogicalProcessors,OsTotalVisibleMemorySize,
CsUserName,TimeZone | Format-List
Section 'Boot Time'
(Get-CimInstance Win32_OperatingSystem).LastBootUpTime
Section 'Local Users'
Get-LocalUser | Select-Object Name,Enabled,LastLogon,Description | Format-Table -AutoSize
Section 'Administrators Group'
Get-LocalGroupMember -Group Administrators |
Select-Object Name,ObjectClass,PrincipalSource | Format-Table -AutoSize
Section 'Disks'
Get-Volume | Where-Object DriveLetter | Select-Object DriveLetter,FileSystemLabel,
@{n='Size(GB)';e={[math]::Round($_.Size / 1GB, 1)}},
@{n='Free(GB)';e={[math]::Round($_.SizeRemaining / 1GB, 1)}} |
Format-Table -AutoSize
Section 'IPv4 Addresses'
Get-NetIPAddress -AddressFamily IPv4 |
Where-Object { $_.InterfaceAlias -notmatch 'Loopback' } |
Select-Object InterfaceAlias,IPAddress,PrefixLength | Format-Table -AutoSize
Section 'Listening TCP Ports'
Get-NetTCPConnection -State Listen |
Select-Object LocalAddress,LocalPort,OwningProcess |
Sort-Object LocalPort -Unique | Format-Table -AutoSize
Section 'Firewall Profiles'
Get-NetFirewallProfile |
Select-Object Name,Enabled,DefaultInboundAction,DefaultOutboundAction |
Format-Table -AutoSize
Section 'SMB Shares'
Get-SmbShare | Select-Object Name,Path,Description | Format-Table -AutoSize
Section 'Defender'
Get-MpComputerStatus |
Select-Object AMRunningMode,AntivirusEnabled,RealTimeProtectionEnabled,
AMEngineVersion,AntivirusSignatureLastUpdated | Format-List
Section 'Installed Apps (non-Microsoft)'
$uninstallPaths = @(
'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*',
'HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
)
Get-ItemProperty $uninstallPaths |
Where-Object { $_.DisplayName -and $_.Publisher -notmatch 'Microsoft' } |
Select-Object DisplayName,DisplayVersion,Publisher,InstallDate |
Sort-Object DisplayName | Format-Table -AutoSize
Section 'Startup Commands'
Get-CimInstance Win32_StartupCommand |
Select-Object Name,Command,Location,User | Format-Table -AutoSize
Section 'Scheduled Tasks (non-Microsoft, enabled)'
Get-ScheduledTask |
Where-Object { $_.State -ne 'Disabled' -and $_.TaskPath -notlike '\Microsoft\*' } |
Select-Object TaskPath,TaskName,State | Format-Table -AutoSize
Section 'SSH Services'
Get-Service sshd,ssh-agent | Format-Table Name,Status,StartType -AutoSize
Section 'Recent Logons (Security 4624, last 48h)'
Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4624; StartTime=(Get-Date).AddHours(-48)} -MaxEvents 50 |
ForEach-Object {
$xml = [xml]$_.ToXml()
$d = @{}
$xml.Event.EventData.Data | ForEach-Object { $d[$_.Name] = $_.'#text' }
[pscustomobject]@{
Time = $_.TimeCreated
LogonType = $d['LogonType']
User = "$($d['TargetDomainName'])\$($d['TargetUserName'])"
IP = $d['IpAddress']
Process = $d['ProcessName']
}
} |
Where-Object { $_.User -notmatch 'SYSTEM|ANONYMOUS|LOCAL SERVICE|NETWORK SERVICE|DWM-|UMFD-|\$$' } |
Format-Table -AutoSize

View File

@@ -0,0 +1,102 @@
[Console]::OutputEncoding = [Text.Encoding]::UTF8
$ErrorActionPreference = 'Continue'
$configPath = Join-Path $PSScriptRoot 'remove-apps-config.json'
if (-not (Test-Path $configPath)) { throw "Config not found: $configPath" }
$cfg = Get-Content $configPath -Raw -Encoding UTF8 | ConvertFrom-Json
$results = @()
function Record([string]$name, [string]$result, [string]$detail='') {
$script:results += [pscustomobject]@{ Name = $name; Result = $result; Detail = $detail }
}
Write-Host "===== Removing Appx packages ====="
foreach ($name in @($cfg.RemoveAppx)) {
$pkgs = @(Get-AppxPackage -AllUsers -Name $name -ErrorAction SilentlyContinue)
$prov = @(Get-AppxProvisionedPackage -Online -ErrorAction SilentlyContinue | Where-Object { $_.DisplayName -eq $name })
if ($pkgs.Count -eq 0 -and $prov.Count -eq 0) {
Write-Host "[=] $name : not installed"
Record $name 'not-installed'
continue
}
foreach ($p in $pkgs) {
try {
Write-Host "[*] Remove-AppxPackage $($p.PackageFullName)"
Remove-AppxPackage -AllUsers -Package $p.PackageFullName -ErrorAction Stop
} catch {
# 0x80073D19 = NonRemovable system package. Worth noting but often unavoidable.
if ($_.Exception.Message -match '0x80073D19|NonRemovable') {
Write-Host "[!] $name marked NonRemovable by Windows - skipping"
Record $name 'nonremovable' $_.Exception.Message
} else {
Write-Host "[!] $name install removal failed: $($_.Exception.Message)"
Record $name 'failed-install' $_.Exception.Message
}
}
}
foreach ($p in $prov) {
try {
Remove-AppxProvisionedPackage -Online -PackageName $p.PackageName -ErrorAction Stop | Out-Null
Write-Host "[*] Remove-AppxProvisionedPackage $($p.PackageName)"
} catch {
# Provisioned removal often fails silently when package was already deprovisioned by other tools.
# Only worth logging, not flagging as a hard failure.
}
}
# Verify post-state
$after = @(Get-AppxPackage -AllUsers -Name $name -ErrorAction SilentlyContinue)
if ($after.Count -eq 0) {
Record $name 'removed'
} elseif (($results | Where-Object Name -eq $name | Select-Object -Last 1).Result -ne 'nonremovable') {
Record $name 'still-present' "after removal attempt: $(($after | Select -Expand PackageFullName) -join ',')"
}
}
Write-Host ""
Write-Host "===== Office (M365) removal ====="
if ($cfg.RemoveOffice) {
$c2rClient = 'C:\Program Files\Common Files\microsoft shared\ClickToRun\OfficeClickToRun.exe'
if (Test-Path $c2rClient) {
Write-Host "[*] Click-to-Run detected - running silent uninstall"
$p = Start-Process -FilePath $c2rClient -ArgumentList 'scenario=uninstall','sourcetype=None','DisplayLevel=False' -Wait -PassThru
Write-Host "[=] OfficeClickToRun exited $($p.ExitCode)"
} else {
Write-Host "[=] No Click-to-Run Office present"
}
$anyOfficeAppx = $false
foreach ($pat in @('Microsoft.MicrosoftOfficeHub','Microsoft.Office.*','Microsoft.OutlookForWindows')) {
$hit = @(Get-AppxPackage -AllUsers -Name $pat -ErrorAction SilentlyContinue)
foreach ($p in $hit) {
$anyOfficeAppx = $true
try {
Write-Host "[*] Remove-AppxPackage $($p.PackageFullName)"
Remove-AppxPackage -AllUsers -Package $p.PackageFullName -ErrorAction Stop
Record $p.Name 'removed'
} catch {
Write-Host "[!] $($p.Name) failed: $($_.Exception.Message)"
Record $p.Name 'failed-install' $_.Exception.Message
}
}
}
if ((-not (Test-Path $c2rClient)) -and (-not $anyOfficeAppx)) {
Write-Host "[=] No Office / M365 traces found - nothing to do"
}
}
Write-Host ""
Write-Host "===== Summary ====="
$byResult = $results | Group-Object Result | Sort-Object Name
foreach ($g in $byResult) {
Write-Host ("{0,-15}: {1}" -f $g.Name, $g.Count)
}
$problem = $results | Where-Object { $_.Result -in 'failed-install','still-present' }
if ($problem) {
Write-Host ""
Write-Host "Needs attention:"
$problem | ForEach-Object { Write-Host " - $($_.Name) [$($_.Result)] $($_.Detail)" }
}

View File

@@ -0,0 +1,82 @@
param(
[ValidateSet('Apply','Revert')]
[string]$Mode = 'Apply',
[switch]$SkipDownload # use existing C:\Users\Admin\RemoveWindowsAi.ps1 instead of re-downloading
)
[Console]::OutputEncoding = [Text.Encoding]::UTF8
$ErrorActionPreference = 'Stop'
# 1. Must be Windows PowerShell 5.1, NOT pwsh 7+
if ($PSVersionTable.PSVersion.Major -ge 7) {
throw "This wrapper must run under Windows PowerShell 5.1 (powershell.exe), not pwsh $($PSVersionTable.PSVersion). Relaunch explicitly with powershell.exe."
}
# 2. Must have Administrator token
$isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not $isAdmin) {
throw "Current session is NOT running as Administrator. RemoveWindowsAi.ps1 requires admin and its self-elevation (UAC RunAs) will fail over SSH. Ensure the SSH user has full admin token."
}
# 3. Fetch upstream script
$workDir = Join-Path $env:TEMP 'RemoveWindowsAI'
$scriptPath = Join-Path $workDir 'RemoveWindowsAi.ps1'
$logPath = Join-Path $workDir ("run-$Mode-$(Get-Date -Format 'yyyyMMdd-HHmmss').log")
New-Item -ItemType Directory -Force -Path $workDir | Out-Null
if (-not $SkipDownload) {
$url = 'https://raw.githubusercontent.com/zoicware/RemoveWindowsAI/main/RemoveWindowsAi.ps1'
Write-Host "[*] Downloading $url"
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Invoke-WebRequest -Uri $url -OutFile $scriptPath -UseBasicParsing
if ((Get-Item $scriptPath).Length -lt 100KB) {
throw "Downloaded script seems too small ($((Get-Item $scriptPath).Length) bytes)"
}
# PowerShell 5.1 reads files without BOM using the system ANSI code page (CP950 on zh-TW),
# which mangles non-ASCII content. Force UTF-8 by prepending a BOM if not already present.
$bytes = [IO.File]::ReadAllBytes($scriptPath)
$hasBom = $bytes.Length -ge 3 -and $bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF
if (-not $hasBom) {
$bom = [byte[]](0xEF, 0xBB, 0xBF)
[IO.File]::WriteAllBytes($scriptPath, $bom + $bytes)
Write-Host "[*] Added UTF-8 BOM"
}
Write-Host "[*] Saved -> $scriptPath ($((Get-Item $scriptPath).Length) bytes)"
} elseif (-not (Test-Path $scriptPath)) {
throw "-SkipDownload set but $scriptPath does not exist"
}
# 4. Build args based on mode
$psArgs = @('-NoProfile','-ExecutionPolicy','Bypass','-File', $scriptPath, '-nonInteractive', '-EnableLogging')
if ($Mode -eq 'Apply') {
$psArgs += @('-AllOptions','-backupMode')
Write-Host "[*] Mode=Apply: -AllOptions -backupMode (backup saved for later revert)"
} else {
$psArgs += @('-AllOptions','-revertMode')
Write-Host "[*] Mode=Revert: -AllOptions -revertMode (requires prior backup)"
}
# 5. Execute and tee output to log
Write-Host "[*] Executing: powershell.exe $($psArgs -join ' ')"
Write-Host "[*] Log -> $logPath"
Write-Host ('-' * 60)
$proc = Start-Process -FilePath 'powershell.exe' -ArgumentList $psArgs `
-NoNewWindow -Wait -PassThru `
-RedirectStandardOutput $logPath -RedirectStandardError "$logPath.err"
Write-Host ('-' * 60)
Get-Content $logPath -ErrorAction SilentlyContinue | Select-Object -Last 80
if (Test-Path "$logPath.err") {
$errs = Get-Content "$logPath.err"
if ($errs) {
Write-Host "--- stderr ---"
$errs
}
}
Write-Host ""
Write-Host "[=] Exit code: $($proc.ExitCode)"
Write-Host "[=] Full log: $logPath"
Write-Host "[!] A reboot is recommended after this operation."
exit $proc.ExitCode

View File

@@ -0,0 +1,51 @@
[Console]::OutputEncoding = [Text.Encoding]::UTF8
$ErrorActionPreference = 'Stop'
# --- 1. Rename local account 'user' -> 'User' ---
$src = 'user'
$dst = 'User'
$u = Get-LocalUser -Name $src -ErrorAction SilentlyContinue
if ($u) {
if ($u.Name -ceq $dst) {
Write-Host "[=] Account is already '$dst'"
} else {
Write-Host "[*] Renaming local account '$($u.Name)' -> '$dst'"
Rename-LocalUser -Name $src -NewName $dst
Write-Host "[OK] Renamed"
}
} else {
$already = Get-LocalUser -Name $dst -ErrorAction SilentlyContinue
if ($already) {
Write-Host "[=] Account '$dst' already exists (no '$src' found). Nothing to rename."
} else {
throw "Neither '$src' nor '$dst' exists as local user"
}
}
# --- 2. Hide 'Admin' from sign-in screen ---
$listPath = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList'
if (-not (Test-Path $listPath)) {
New-Item -Path $listPath -Force | Out-Null
Write-Host "[*] Created $listPath"
}
New-ItemProperty -Path $listPath -Name 'Admin' -Value 0 -PropertyType DWord -Force | Out-Null
Write-Host "[OK] Hidden 'Admin' from sign-in screen (SpecialAccounts\UserList\Admin = 0)"
Write-Host ""
Write-Host "=== Post-state ==="
Get-LocalUser | Select-Object Name,Enabled,LastLogon | Format-Table -AutoSize
$lst = Get-ItemProperty -Path $listPath -ErrorAction SilentlyContinue
if ($lst) {
Write-Host "UserList values:"
$lst.PSObject.Properties | Where-Object { $_.Name -notmatch '^PS' } | ForEach-Object {
Write-Host (" {0} = {1}" -f $_.Name, $_.Value)
}
}
Write-Host ""
Write-Host "Notes:"
Write-Host " - Account SIDs don't change. C:\Users\user profile folder stays with lowercase name"
Write-Host " (NTFS is case-insensitive so all apps keep working)."
Write-Host " - Admin can still sign in: click 'Other user' on the lock screen and type 'Admin'."

View File

@@ -0,0 +1,97 @@
[Console]::OutputEncoding = [Text.Encoding]::UTF8
$ErrorActionPreference = 'Continue'
Write-Host "[*] Setting desktop icons for User account"
# Icon GUIDs
$computerGUID = "{20D04FE0-3AEA-1069-A2D8-08002B30309D}"
$controlPanelGUID = "{5399E694-6CE5-4D6C-8FCE-1D8870FDCBA0}"
$recycleGUID = "{645FF040-5081-101B-9F08-00AA002F954E}"
# Get User SID
try {
$user = New-Object System.Security.Principal.NTAccount("User")
$userSID = $user.Translate([System.Security.Principal.SecurityIdentifier]).Value
Write-Host "[*] User SID: $userSID"
} catch {
Write-Host "[!] Could not get user SID, trying alternative method"
# Try to get SID from registry
$userProfiles = Get-ChildItem "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList"
foreach ($profile in $userProfiles) {
$profileData = Get-ItemProperty -Path $profile.PSPath -ErrorAction SilentlyContinue
if ($profileData.ProfileImagePath -like "*\User") {
$userSID = $profile.PSChildName
Write-Host "[*] Found User SID: $userSID"
break
}
}
}
if (-not $userSID) {
Write-Host "[!] Could not determine User SID" -ForegroundColor Red
exit 1
}
# Check if user hive is loaded (user is logged in)
$userHivePath = "HKU:\$userSID"
if (Test-Path $userHivePath) {
Write-Host "[*] User is currently logged in, modifying active hive"
$desktopIconsPath = "$userHivePath\Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\NewStartPanel"
$classicIconsPath = "$userHivePath\Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\ClassicStartMenu"
# Ensure registry paths exist
foreach ($path in @($desktopIconsPath, $classicIconsPath)) {
if (-not (Test-Path $path)) {
New-Item -Path $path -Force | Out-Null
Write-Host " Created registry path"
}
}
# Enable desktop icons
$icons = @{
"Computer" = $computerGUID
"Control Panel" = $controlPanelGUID
"Recycle Bin" = $recycleGUID
}
foreach ($iconName in $icons.Keys) {
$guid = $icons[$iconName]
Set-ItemProperty -Path $desktopIconsPath -Name $guid -Value 0 -Type DWord
Set-ItemProperty -Path $classicIconsPath -Name $guid -Value 0 -Type DWord
Write-Host " Enabled: $iconName"
}
Write-Host "[*] Refreshing desktop for logged-in user"
# Create a script to run as the user to refresh the desktop
$refreshScript = @"
Add-Type -TypeDefinition 'using System; using System.Runtime.InteropServices; public class Win32 { [DllImport("user32.dll")] public static extern bool InvalidateRect(IntPtr hWnd, IntPtr lpRect, bool bErase); [DllImport("user32.dll")] public static extern IntPtr GetDesktopWindow(); }'
[Win32]::InvalidateRect([Win32]::GetDesktopWindow(), [IntPtr]::Zero, $true)
"@
try {
# Try to refresh the desktop
Invoke-Expression $refreshScript
Write-Host " Desktop refresh attempted"
} catch {
Write-Host " Could not refresh desktop automatically"
}
Write-Host ""
Write-Host "[OK] Desktop icons configured for active User session"
Write-Host "Icons should appear shortly. If not visible:"
Write-Host "1. Right-click desktop > Refresh"
Write-Host "2. Log out and log back in as User"
} else {
Write-Host "[*] User is not currently logged in"
Write-Host "[!] Cannot modify registry while user is logged out"
Write-Host ""
Write-Host "Please:"
Write-Host "1. Log in as User"
Write-Host "2. Run this script again"
Write-Host "3. Or reboot and log in as User, then run the script"
}

View File

@@ -0,0 +1,138 @@
[Console]::OutputEncoding = [Text.Encoding]::UTF8
$ErrorActionPreference = 'Continue'
Write-Host "[*] Setting up network drive R: and removing desktop shortcut"
# File paths
$shortcutPath = "C:\Users\User\Desktop\Network Share (RD).lnk"
$networkPath = "\\192.168.88.231\rd"
$driveLetter = "R:"
Write-Host "[*] Step 1: Removing desktop shortcut"
if (Test-Path $shortcutPath) {
try {
Remove-Item $shortcutPath -Force
Write-Host "[OK] Desktop shortcut removed: Network Share (RD).lnk"
} catch {
Write-Host "[!] Failed to remove shortcut: $($_.Exception.Message)"
}
} else {
Write-Host " Desktop shortcut not found (already removed)"
}
Write-Host "[*] Step 2: Checking current network drives"
# Check existing drives
$existingDrives = Get-WmiObject -Class Win32_LogicalDisk | Select-Object DeviceID, DriveType, ProviderName
$networkDrives = $existingDrives | Where-Object { $_.DriveType -eq 4 }
if ($networkDrives) {
Write-Host " Current network drives:"
foreach ($drive in $networkDrives) {
Write-Host " - $($drive.DeviceID) -> $($drive.ProviderName)"
}
} else {
Write-Host " No network drives currently mapped"
}
Write-Host "[*] Step 3: Mapping network drive R:"
# Check if R: is already in use
$rDriveExists = $existingDrives | Where-Object { $_.DeviceID -eq $driveLetter }
if ($rDriveExists) {
Write-Host " R: drive already exists"
if ($rDriveExists.ProviderName -eq $networkPath) {
Write-Host "[OK] R: is already mapped to $networkPath"
exit 0
} else {
Write-Host " R: is mapped to: $($rDriveExists.ProviderName)"
Write-Host " Disconnecting existing mapping..."
try {
& net use $driveLetter /delete /yes
Write-Host " Existing R: mapping removed"
} catch {
Write-Host "[!] Failed to disconnect R: drive"
}
}
}
Write-Host " Mapping $networkPath to $driveLetter"
# Test network connectivity first
Write-Host "[*] Step 4: Testing network connectivity"
try {
$testConnection = Test-NetConnection -ComputerName "192.168.88.231" -Port 445 -WarningAction SilentlyContinue
if ($testConnection.TcpTestSucceeded) {
Write-Host "[OK] Network connection to 192.168.88.231:445 successful"
} else {
Write-Host "[!] Warning: Cannot reach 192.168.88.231:445"
}
} catch {
Write-Host "[!] Network test failed: $($_.Exception.Message)"
}
# Map the network drive
Write-Host "[*] Step 5: Creating network drive mapping"
try {
# Use net use command for mapping
$result = & net use $driveLetter $networkPath 2>&1
if ($LASTEXITCODE -eq 0) {
Write-Host "[OK] Network drive mapped successfully!"
Write-Host " $driveLetter -> $networkPath"
# Verify the mapping
Start-Sleep -Seconds 2
$verification = Get-WmiObject -Class Win32_LogicalDisk | Where-Object { $_.DeviceID -eq $driveLetter }
if ($verification) {
Write-Host "[OK] Drive mapping verified"
Write-Host " Drive type: $($verification.DriveType) (4 = Network)"
Write-Host " Provider: $($verification.ProviderName)"
}
} else {
Write-Host "[!] Network drive mapping failed"
Write-Host " Error output: $result"
# Provide troubleshooting info
Write-Host ""
Write-Host "Possible solutions:"
Write-Host "1. Run as Administrator: net use R: \\192.168.88.231\rd"
Write-Host "2. With credentials: net use R: \\192.168.88.231\rd /user:username"
Write-Host "3. Check if the share exists and is accessible"
Write-Host "4. Verify network connectivity to 192.168.88.231"
}
} catch {
Write-Host "[!] Exception during mapping: $($_.Exception.Message)"
}
Write-Host ""
Write-Host "[*] Final status check"
# Final verification
$finalDrives = Get-WmiObject -Class Win32_LogicalDisk | Where-Object { $_.DriveType -eq 4 }
if ($finalDrives) {
Write-Host "Current network drives:"
foreach ($drive in $finalDrives) {
if ($drive.DeviceID -eq $driveLetter) {
Write-Host "[OK] $($drive.DeviceID) -> $($drive.ProviderName) (SUCCESS)"
} else {
Write-Host " $($drive.DeviceID) -> $($drive.ProviderName)"
}
}
} else {
Write-Host "No network drives mapped"
}
Write-Host ""
Write-Host "Setup complete!"
Write-Host "- Desktop shortcut removed"
Write-Host "- Network drive R: mapping attempted"
Write-Host ""
Write-Host "Access the network share via:"
Write-Host "1. File Explorer > This PC > R: drive"
Write-Host "2. Address bar: R:\"
Write-Host "3. Run dialog: R:\"

View File

@@ -0,0 +1,102 @@
[Console]::OutputEncoding = [Text.Encoding]::UTF8
$ErrorActionPreference = 'Continue'
Write-Host "[*] Setting up network share access"
# Network share path
$sharePath = "\\192.168.88.231\rd"
$shortcutPath = "C:\Users\User\Desktop\Network Share (RD).lnk"
Write-Host "[*] Testing connection to network share"
Write-Host " Target: $sharePath"
# Test network connectivity
try {
$testConnection = Test-NetConnection -ComputerName "192.168.88.231" -Port 445 -WarningAction SilentlyContinue
if ($testConnection.TcpTestSucceeded) {
Write-Host "[OK] Network connection successful (Port 445 accessible)"
} else {
Write-Host "[!] Warning: Port 445 not accessible - SMB might be blocked"
}
} catch {
Write-Host "[!] Network test failed: $($_.Exception.Message)"
}
Write-Host "[*] Creating desktop shortcut to network share"
# Create shortcut using WScript.Shell
try {
$WshShell = New-Object -comObject WScript.Shell
$Shortcut = $WshShell.CreateShortcut($shortcutPath)
$Shortcut.TargetPath = $sharePath
$Shortcut.WorkingDirectory = $sharePath
$Shortcut.IconLocation = "shell32.dll,4" # Folder icon
$Shortcut.Description = "Network Share - RD"
$Shortcut.Save()
Write-Host "[OK] Desktop shortcut created: Network Share (RD).lnk"
} catch {
Write-Host "[!] Failed to create shortcut: $($_.Exception.Message)"
}
Write-Host "[*] Testing share access"
# Test if we can access the share
try {
if (Test-Path $sharePath) {
Write-Host "[OK] Network share is accessible"
# Try to list contents
$items = Get-ChildItem $sharePath -ErrorAction SilentlyContinue | Select-Object -First 5
if ($items) {
Write-Host " Found $($items.Count) items in share"
} else {
Write-Host " Share appears empty or no read permission"
}
} else {
Write-Host "[!] Network share not accessible"
Write-Host " Possible issues:"
Write-Host " - Share doesn't exist"
Write-Host " - No network access"
Write-Host " - Authentication required"
Write-Host " - SMB protocol blocked"
}
} catch {
Write-Host "[!] Error accessing share: $($_.Exception.Message)"
}
Write-Host "[*] Checking if drive mapping is needed"
# Check if we should map as network drive
$availableDrives = Get-WmiObject -Class Win32_LogicalDisk | Where-Object {$_.DriveType -eq 3} | Select-Object -ExpandProperty DeviceID
$networkDrives = Get-WmiObject -Class Win32_LogicalDisk | Where-Object {$_.DriveType -eq 4} | Select-Object -ExpandProperty DeviceID
Write-Host " Current network drives: $($networkDrives -join ', ')"
# Suggest mapping to Z: drive if not already used
if ("Z:" -notin ($availableDrives + $networkDrives)) {
Write-Host "[*] Attempting to map network drive Z:"
try {
& net use Z: $sharePath
Write-Host "[OK] Network drive Z: mapped successfully"
} catch {
Write-Host "[!] Drive mapping failed - may require credentials"
Write-Host " Manual mapping: net use Z: $sharePath /user:username"
}
} else {
Write-Host " Z: drive already in use"
}
Write-Host ""
Write-Host "[OK] Network share setup complete!"
Write-Host ""
Write-Host "Access methods:"
Write-Host "1. Double-click 'Network Share (RD).lnk' on desktop"
Write-Host "2. Type '$sharePath' in File Explorer address bar"
if ("Z:" -notin $availableDrives) {
Write-Host "3. Use Z: drive if mapping was successful"
}
Write-Host ""
Write-Host "If access is denied, you may need to:"
Write-Host "- Right-click shortcut > Run as administrator"
Write-Host "- Provide network credentials when prompted"

View File

@@ -0,0 +1,89 @@
[Console]::OutputEncoding = [Text.Encoding]::UTF8
$ErrorActionPreference = 'Continue'
Write-Host "[*] Setting up RDP connection with saved credentials"
# RDP file path on desktop
$rdpFile = "C:\Users\User\Desktop\Remote-PC.rdp"
# RDP file content with credentials
$rdpContent = @"
screen mode id:i:2
use multimon:i:0
desktopwidth:i:1920
desktopheight:i:1080
session bpp:i:32
winposstr:s:0,3,0,0,800,600
compression:i:1
keyboardhook:i:2
audiocapturemode:i:0
videoplaybackmode:i:1
connection type:i:7
networkautodetect:i:1
bandwidthautodetect:i:1
displayconnectionbar:i:1
enableworkspacereconnect:i:0
disable wallpaper:i:0
allow font smoothing:i:0
allow desktop composition:i:0
disable full window drag:i:1
disable menu anims:i:1
disable themes:i:0
disable cursor setting:i:0
bitmapcachepersistenable:i:1
full address:s:192.168.88.21
audiomode:i:0
redirectprinters:i:1
redirectcomports:i:0
redirectsmartcards:i:1
redirectclipboard:i:1
redirectposdevices:i:0
autoreconnection enabled:i:1
authentication level:i:2
prompt for credentials:i:0
negotiate security layer:i:1
remoteapplicationmode:i:0
alternate shell:s:
shell working directory:s:
gatewayhostname:s:
gatewayusagemethod:i:4
gatewaycredentialssource:i:4
gatewayprofileusagemethod:i:0
promptcredentialonce:i:0
gatewaybrokeringtype:i:0
use redirection server name:i:0
rdgiskdcproxy:i:0
kdcproxyname:s:
drivestoredirect:s:
username:s:ChiaYing
domain:s:
"@
# Write RDP file
$rdpContent | Out-File -FilePath $rdpFile -Encoding UTF8
Write-Host "[*] RDP file created: $rdpFile"
# Add credential to Windows Credential Manager
Write-Host "[*] Adding credentials to Windows Credential Manager"
try {
# Use cmdkey to add credential
& cmdkey /generic:"TERMSRV/192.168.88.21" /user:"ChiaYing" /pass:"!ChiaYing"
Write-Host "[OK] Credentials saved to Credential Manager"
} catch {
Write-Host "[!] Failed to save credentials: $($_.Exception.Message)"
}
# Verify the RDP file was created
if (Test-Path $rdpFile) {
$fileInfo = Get-Item $rdpFile
Write-Host "[OK] RDP file ready: $($fileInfo.Name) ($($fileInfo.Length) bytes)"
Write-Host ""
Write-Host "Usage:"
Write-Host "1. Double-click 'Remote-PC.rdp' on desktop"
Write-Host "2. Connection should start automatically with saved credentials"
Write-Host "3. If prompted for password, enter: !ChiaYing"
} else {
Write-Host "[!] Failed to create RDP file"
exit 1
}

View File

@@ -0,0 +1,150 @@
[Console]::OutputEncoding = [Text.Encoding]::UTF8
$ErrorActionPreference = 'Stop'
$configPath = Join-Path $PSScriptRoot 'thunderbird-config.json'
if (-not (Test-Path $configPath)) { throw "Config not found: $configPath" }
$cfg = Get-Content $configPath -Raw -Encoding UTF8 | ConvertFrom-Json
$socketMap = @{ 'none' = 0; 'STARTTLS' = 2; 'SSL' = 3 }
$authMap = @{ 'normal' = 3; 'encrypted' = 4; 'ntlm' = 8; 'gssapi' = 7; 'oauth2' = 10 }
if (-not $socketMap.ContainsKey($cfg.Incoming.SocketType)) {
throw "Incoming.SocketType must be one of: $($socketMap.Keys -join ', ')"
}
if (-not $socketMap.ContainsKey($cfg.Outgoing.SocketType)) {
throw "Outgoing.SocketType must be one of: $($socketMap.Keys -join ', ')"
}
if (-not $authMap.ContainsKey($cfg.Incoming.AuthMethod)) {
throw "Incoming.AuthMethod must be one of: $($authMap.Keys -join ', ')"
}
if (-not $authMap.ContainsKey($cfg.Outgoing.AuthMethod)) {
throw "Outgoing.AuthMethod must be one of: $($authMap.Keys -join ', ')"
}
$winUser = $cfg.WindowsUser
$appRoot = "C:\Users\$winUser\AppData\Roaming\Thunderbird"
$profilesDir = Join-Path $appRoot 'Profiles'
$profileName = $cfg.ProfileName
$profilePath = Join-Path $profilesDir $profileName
$iniPath = Join-Path $appRoot 'profiles.ini'
if (-not (Test-Path "C:\Users\$winUser")) {
throw "Windows user '$winUser' not found (no C:\Users\$winUser folder)"
}
# Stop any running Thunderbird so we don't fight it
Get-Process thunderbird -ErrorAction SilentlyContinue | Stop-Process -Force
New-Item -ItemType Directory -Force -Path $profilePath | Out-Null
$incSocket = $socketMap[$cfg.Incoming.SocketType]
$outSocket = $socketMap[$cfg.Outgoing.SocketType]
$incAuth = $authMap[$cfg.Incoming.AuthMethod]
$outAuth = $authMap[$cfg.Outgoing.AuthMethod]
$prefs = @"
// Generated by setup-thunderbird.ps1
user_pref("mail.shell.checkDefaultClient", false);
user_pref("mailnews.start_page.enabled", false);
user_pref("mail.accountmanager.accounts", "account1,account2");
user_pref("mail.accountmanager.defaultaccount", "account1");
user_pref("mail.accountmanager.localfoldersserver", "server2");
user_pref("mail.account.account1.identities", "id1");
user_pref("mail.account.account1.server", "server1");
user_pref("mail.account.account2.server", "server2");
user_pref("mail.server.server1.type", "$($cfg.Incoming.Type)");
user_pref("mail.server.server1.hostname", "$($cfg.Incoming.Hostname)");
user_pref("mail.server.server1.port", $($cfg.Incoming.Port));
user_pref("mail.server.server1.socketType", $incSocket);
user_pref("mail.server.server1.userName", "$($cfg.Incoming.Username)");
user_pref("mail.server.server1.authMethod", $incAuth);
user_pref("mail.server.server1.name", "$($cfg.Identity.Email)");
user_pref("mail.server.server1.login_at_startup", true);
user_pref("mail.server.server1.check_new_mail", true);
user_pref("mail.server.server2.type", "none");
user_pref("mail.server.server2.hostname", "Local Folders");
user_pref("mail.server.server2.name", "Local Folders");
user_pref("mail.server.server2.userName", "nobody");
user_pref("mail.identity.id1.fullName", "$($cfg.Identity.FullName)");
user_pref("mail.identity.id1.useremail", "$($cfg.Identity.Email)");
user_pref("mail.identity.id1.smtpServer", "smtp1");
user_pref("mail.identity.id1.valid", true);
user_pref("mail.smtpservers", "smtp1");
user_pref("mail.smtp.defaultserver", "smtp1");
user_pref("mail.smtpserver.smtp1.hostname", "$($cfg.Outgoing.Hostname)");
user_pref("mail.smtpserver.smtp1.port", $($cfg.Outgoing.Port));
user_pref("mail.smtpserver.smtp1.try_ssl", $outSocket);
user_pref("mail.smtpserver.smtp1.username", "$($cfg.Outgoing.Username)");
user_pref("mail.smtpserver.smtp1.authMethod", $outAuth);
user_pref("mail.smtpserver.smtp1.description", "$($cfg.Outgoing.Hostname)");
"@
$prefsPath = Join-Path $profilePath 'prefs.js'
Set-Content -Path $prefsPath -Value $prefs -Encoding UTF8
Write-Host "[*] Wrote prefs.js -> $prefsPath"
# profiles.ini: Thunderbird 72+ selects profile via [Install<HASH>] section, not Default=1 on Profile.
# Merge: preserve existing Profile/Install entries, force our profile as default everywhere.
$profileRelPath = "Profiles/$profileName"
if (Test-Path $iniPath) {
$iniRaw = Get-Content $iniPath -Raw
# Redirect any existing Install<HASH> block to our profile
$iniRaw = [regex]::Replace($iniRaw, '(?m)^Default=Profiles/[^\r\n]+', "Default=$profileRelPath")
# Clear Default=1 from other Profile sections so only ours is default
$iniRaw = [regex]::Replace($iniRaw, '(?ms)(\[Profile\d+\][^\[]*?Name=(?!' + [regex]::Escape($profileName) + ')[^\r\n]+[^\[]*?)Default=1\s*', '$1')
# If our Profile entry is missing, append it
if ($iniRaw -notmatch "(?m)^Name=$([regex]::Escape($profileName))\s*$") {
$nextIdx = 0
while ($iniRaw -match "(?m)^\[Profile$nextIdx\]") { $nextIdx++ }
$append = @"
[Profile$nextIdx]
Name=$profileName
IsRelative=1
Path=$profileRelPath
Default=1
"@
$iniRaw = $iniRaw.TrimEnd() + "`r`n" + $append + "`r`n"
}
Set-Content -Path $iniPath -Value $iniRaw -Encoding ASCII
Write-Host "[*] Merged profiles.ini -> $iniPath"
} else {
$ini = @"
[General]
StartWithLastProfile=1
Version=2
[Profile0]
Name=$profileName
IsRelative=1
Path=$profileRelPath
Default=1
"@
Set-Content -Path $iniPath -Value $ini -Encoding ASCII
Write-Host "[*] Wrote profiles.ini -> $iniPath"
}
# Also update installs.ini (Thunderbird 72+) if present
$installsIni = Join-Path $appRoot 'installs.ini'
if (Test-Path $installsIni) {
$raw = Get-Content $installsIni -Raw
$raw = [regex]::Replace($raw, '(?m)^Default=Profiles/[^\r\n]+', "Default=$profileRelPath")
Set-Content -Path $installsIni -Value $raw -Encoding ASCII
Write-Host "[*] Updated installs.ini -> $installsIni"
}
# If we're running as a different user than the profile target, fix ownership so they can read/write
if ($winUser -ne $env:USERNAME) {
Write-Host "[*] Adjusting ACL for '$winUser' on $appRoot"
& icacls $appRoot /grant "${winUser}:(OI)(CI)F" /T /Q | Out-Null
}
Write-Host ""
Write-Host "[OK] Thunderbird profile '$profileName' configured for Windows user '$winUser'"
Write-Host " Identity: $($cfg.Identity.FullName) <$($cfg.Identity.Email)>"
Write-Host " Incoming: $($cfg.Incoming.Type) $($cfg.Incoming.Hostname):$($cfg.Incoming.Port) ($($cfg.Incoming.SocketType))"
Write-Host " Outgoing: smtp $($cfg.Outgoing.Hostname):$($cfg.Outgoing.Port) ($($cfg.Outgoing.SocketType))"
Write-Host ""
Write-Host "Next step: log in as '$winUser', start Thunderbird; it will prompt for the password on first connection."

View File

@@ -0,0 +1,111 @@
[Console]::OutputEncoding = [Text.Encoding]::UTF8
$ErrorActionPreference = 'SilentlyContinue'
$pass = 0; $fail = 0
function Check($label, [bool]$ok, $detail='') {
if ($ok) { $script:pass++; $mark = '[OK] ' } else { $script:fail++; $mark = '[FAIL]' }
Write-Host ("{0} {1}" -f $mark, $label)
if ($detail) { Write-Host (" {0}" -f $detail) }
}
Write-Host "===== Services (expect removed) ====="
# Only actual AI services that RemoveWindowsAI targets.
foreach ($s in @('WSAIFabricSvc','AarSvc')) {
$svc = Get-Service -Name $s -ErrorAction SilentlyContinue
$detail = if ($svc) { "still present (Status=$($svc.Status))" } else { "gone" }
Check "service '$s' removed" (-not $svc) $detail
}
Write-Host ""
Write-Host "===== Appx packages (expect removed) ====="
foreach ($pat in @('Microsoft.Copilot','Microsoft.MicrosoftCopilot','Microsoft.Windows.Copilot','MicrosoftWindows.Client.AIX','MicrosoftWindows.Client.CoreAI')) {
$pkg = Get-AppxPackage -AllUsers -Name "$pat*" -ErrorAction SilentlyContinue
$detail = if ($pkg) { "still present: $(($pkg | Select -Expand Name) -join ',')" } else { "not installed" }
Check "Appx '$pat*' removed" (-not $pkg) $detail
}
Write-Host ""
Write-Host "===== Recall ====="
$recall = Get-WindowsOptionalFeature -Online -FeatureName 'Recall' -ErrorAction SilentlyContinue
if ($recall) {
Check "Recall optional feature disabled" ($recall.State -eq 'Disabled') "state=$($recall.State)"
} else {
Check "Recall optional feature absent" $true "feature not found"
}
$rct = @(Get-ScheduledTask -TaskPath '\Microsoft\Windows\WindowsAI\*' -ErrorAction SilentlyContinue)
$detail = if ($rct.Count -gt 0) { "remaining: $(($rct | Select -Expand TaskName) -join ',')" } else { "none" }
Check "WindowsAI scheduled tasks removed" ($rct.Count -eq 0) $detail
Write-Host ""
Write-Host "===== Policy registry ====="
# Copilot's turn-off flag is under HKCU (tool writes to current user hive).
# WindowsAI policy keys are machine-wide (HKLM).
$policies = @(
@{ Path = 'HKCU:\SOFTWARE\Policies\Microsoft\Windows\WindowsCopilot'; Name = 'TurnOffWindowsCopilot'; Expect = 1 },
@{ Path = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsAI'; Name = 'DisableAIDataAnalysis'; Expect = 1 },
@{ Path = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsAI'; Name = 'DisableClickToDo'; Expect = 1 },
@{ Path = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsAI'; Name = 'AllowRecallEnablement'; Expect = 0 }
)
foreach ($p in $policies) {
$val = (Get-ItemProperty -Path $p.Path -Name $p.Name -ErrorAction SilentlyContinue).($p.Name)
$shortPath = $p.Path -replace '^HK..:\\SOFTWARE\\',''
Check "$shortPath : $($p.Name) == $($p.Expect)" ($val -eq $p.Expect) "actual=$val"
}
Write-Host ""
Write-Host "===== Notepad Rewrite (per-user, populated on first Notepad launch) ====="
# Key only appears after a user opens Notepad. Fail only if any user hive has RewriteEnabled=1.
$bad = @()
Get-ChildItem 'Registry::HKEY_USERS' -ErrorAction SilentlyContinue | ForEach-Object {
$np = "Registry::$($_.Name)\Software\Microsoft\Notepad"
$v = (Get-ItemProperty $np -Name RewriteEnabled -ErrorAction SilentlyContinue).RewriteEnabled
if ($v -eq 1) { $bad += "$($_.Name)=1" }
}
$d = if ($bad) { "enabled in: $($bad -join ',')" } else { "not enabled in any user hive" }
Check "Notepad Rewrite not enabled anywhere" (-not $bad) $d
Write-Host ""
Write-Host "===== IntegratedServicesRegionPolicySet (Copilot entries) ====="
$jsonPath = 'C:\Windows\System32\IntegratedServicesRegionPolicySet.json'
if (Test-Path $jsonPath) {
$j = Get-Content $jsonPath -Raw | ConvertFrom-Json
$copilot = @($j.policies | Where-Object { ($_ | ConvertTo-Json -Depth 3) -match '[Cc]opilot' })
$disabled = @($copilot | Where-Object { $_.defaultState -eq 'disabled' })
$ok = ($copilot.Count -gt 0) -and ($disabled.Count -eq $copilot.Count)
Check "all Copilot policies disabled" $ok "disabled $($disabled.Count) of $($copilot.Count) Copilot entries"
} else {
Check "IntegratedServicesRegionPolicySet.json present" $false "file missing"
}
Write-Host ""
Write-Host "===== Update cleanup safety net ====="
$uct = Get-ScheduledTask -TaskName '*RemoveAI*' -ErrorAction SilentlyContinue
$uctDetail = if ($uct) { "found: $($uct.TaskName), state=$($uct.State)" } else { "missing" }
Check "RemoveAI update-cleanup scheduled task exists" ([bool]$uct) $uctDetail
Write-Host ""
Write-Host "===== Leftover AI SystemApps (expect gone) ====="
# Only check SystemApps dirs and WindowsApps — DLLs in System32 are protected and not
# expected to be deleted; the services/executables are what matter.
$paths = @(
'C:\Windows\SystemApps\MicrosoftWindows.Client.CoPilot_cw5n1h2txyewy',
'C:\Windows\SystemApps\MicrosoftWindows.Client.AIX_cw5n1h2txyewy'
)
foreach ($p in $paths) {
$hit = Get-Item -Path $p -ErrorAction SilentlyContinue
$d = if ($hit) { "still exists" } else { "gone" }
Check "path gone: $p" (-not $hit) $d
}
$wap = @(Get-ChildItem 'C:\Program Files\WindowsApps' -Filter 'Microsoft.Copilot_*' -ErrorAction SilentlyContinue)
$d = if ($wap.Count -gt 0) { "$($wap.Count) dir(s)" } else { "none" }
Check "WindowsApps Microsoft.Copilot_* gone" ($wap.Count -eq 0) $d
Write-Host ""
Write-Host "===== Restore point ====="
$rps = Get-ComputerRestorePoint -ErrorAction SilentlyContinue | Where-Object { $_.Description -match 'RemoveWindowsAI' }
$rpDetail = if ($rps) { "found: $(($rps | Select -Expand Description) -join ',')" } else { "none" }
Check "RemoveWindowsAI restore point exists" ([bool]$rps) $rpDetail
Write-Host ""
Write-Host "===== Summary ====="
Write-Host ("PASS: {0} FAIL: {1}" -f $pass, $fail)

View File

@@ -0,0 +1,106 @@
[Console]::OutputEncoding = [Text.Encoding]::UTF8
$ErrorActionPreference = 'SilentlyContinue'
$pass = 0; $fail = 0
function Check($label, [bool]$ok, $detail='') {
if ($ok) { $script:pass++; $mark = '[OK] ' } else { $script:fail++; $mark = '[FAIL]' }
Write-Host ("{0} {1}" -f $mark, $label)
if ($detail) { Write-Host (" {0}" -f $detail) }
}
$userHives = Get-ChildItem 'Registry::HKEY_USERS' |
Where-Object { $_.Name -match 'S-1-5-21-' -and $_.Name -notmatch '_Classes$' } |
ForEach-Object { $_.Name }
function Get-UserRegValue {
param([string]$SubPath, [string]$Name)
$hits = @()
foreach ($h in $userHives) {
$p = "Registry::$h\$SubPath"
$v = (Get-ItemProperty -Path $p -Name $Name -ErrorAction SilentlyContinue).$Name
if ($null -ne $v) { $hits += [pscustomobject]@{ Hive=$h; Value=$v } }
}
return $hits
}
Write-Host "===== Appx packages removed ====="
foreach ($name in @('Microsoft.GamingApp','Microsoft.XboxGameOverlay','Microsoft.XboxGamingOverlay','Microsoft.windowscommunicationsapps','Microsoft.People','Microsoft.OutlookForWindows','Microsoft.BingSearch','Microsoft.Copilot','Microsoft.StartExperiencesApp')) {
$pkg = Get-AppxPackage -AllUsers -Name $name -ErrorAction SilentlyContinue
$detail = if ($pkg) { "still present" } else { "gone" }
Check "Appx '$name' removed" (-not $pkg) $detail
}
Write-Host ""
Write-Host "===== Telemetry (HKLM) ====="
$val = (Get-ItemProperty 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Policies\DataCollection' -Name AllowTelemetry).AllowTelemetry
Check "Policies\DataCollection\AllowTelemetry == 0" ($val -eq 0) "actual=$val"
Write-Host ""
Write-Host "===== Widgets / News & Interests (HKLM) ====="
$val = (Get-ItemProperty 'HKLM:\Software\Policies\Microsoft\Dsh' -Name AllowNewsAndInterests).AllowNewsAndInterests
Check "Dsh\AllowNewsAndInterests == 0" ($val -eq 0) "actual=$val"
Write-Host ""
Write-Host "===== GameDVR (HKLM policy + per-user) ====="
$val = (Get-ItemProperty 'HKLM:\Software\Policies\Microsoft\Windows\GameDVR' -Name AllowGameDVR).AllowGameDVR
Check "GameDVR policy AllowGameDVR == 0" ($val -eq 0) "actual=$val"
$userDVR = Get-UserRegValue -SubPath 'System\GameConfigStore' -Name 'GameDVR_Enabled'
$match = @($userDVR | Where-Object { $_.Value -eq 0 })
Check "per-user GameDVR_Enabled == 0" ($match.Count -gt 0) "disabled in $($match.Count)/$($userDVR.Count) user hives"
Write-Host ""
Write-Host "===== Update behavior ====="
$val = (Get-ItemProperty 'HKLM:\Software\Policies\Microsoft\Windows\WindowsUpdate\AU' -Name NoAutoRebootWithLoggedOnUsers).NoAutoRebootWithLoggedOnUsers
Check "WindowsUpdate\AU\NoAutoRebootWithLoggedOnUsers == 1" ($val -eq 1) "actual=$val"
Write-Host ""
Write-Host "===== Edge ads / Settings ads ====="
foreach ($c in @(
@{ Path='HKLM:\Software\Policies\Microsoft\Edge'; Name='ShowRecommendationsEnabled'; Expect=0 },
@{ Path='HKLM:\Software\Policies\Microsoft\Edge'; Name='HubsSidebarEnabled'; Expect=0 }
)) {
$val = (Get-ItemProperty -Path $c.Path -Name $c.Name -ErrorAction SilentlyContinue).($c.Name)
$short = $c.Path -replace '^HKLM:\\',''
Check "$short : $($c.Name) == $($c.Expect)" ($val -eq $c.Expect) "actual=$val"
}
Write-Host ""
Write-Host "===== Bing / Search suggestions (per-user) ====="
foreach ($c in @(
@{ Sub='Software\Policies\Microsoft\Windows\Explorer'; Name='DisableSearchBoxSuggestions'; Expect=1; Desc='Bing web search blocked in Start/Search' },
@{ Sub='Software\Microsoft\Windows\CurrentVersion\SearchSettings'; Name='IsDynamicSearchBoxEnabled'; Expect=0; Desc='Search highlights disabled' }
)) {
$hits = Get-UserRegValue -SubPath $c.Sub -Name $c.Name
$match = @($hits | Where-Object { $_.Value -eq $c.Expect })
Check $c.Desc ($match.Count -gt 0) "$($match.Count) of $($hits.Count) user hives match"
}
Write-Host ""
Write-Host "===== Spotlight (per-user) ====="
$hits = Get-UserRegValue -SubPath 'Software\Policies\Microsoft\Windows\CloudContent' -Name 'DisableSpotlightCollectionOnDesktop'
$match = @($hits | Where-Object { $_.Value -eq 1 })
Check 'Desktop Spotlight disabled' ($match.Count -gt 0) "$($match.Count) of $($hits.Count) user hives match"
Write-Host ""
Write-Host "===== Explorer / UI (per-user) ====="
$uiChecks = @(
@{ Sub='Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced'; Name='HideFileExt'; Expect=0; Desc='Show known file extensions' },
@{ Sub='Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced'; Name='Hidden'; Expect=1; Desc='Show hidden items' },
@{ Sub='Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced'; Name='TaskbarAl'; Expect=0; Desc='Taskbar aligned left' },
@{ Sub='Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced'; Name='ShowTaskViewButton'; Expect=0; Desc='Taskview button hidden' },
@{ Sub='Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced'; Name='LaunchTo'; Expect=1; Desc='Explorer opens to This PC' },
@{ Sub='Software\Microsoft\Windows\CurrentVersion\Themes\Personalize'; Name='AppsUseLightTheme'; Expect=0; Desc='Dark mode for apps' },
@{ Sub='Software\Microsoft\Windows\CurrentVersion\Themes\Personalize'; Name='SystemUsesLightTheme'; Expect=0; Desc='Dark mode for system' }
)
foreach ($r in $uiChecks) {
$hits = Get-UserRegValue -SubPath $r.Sub -Name $r.Name
$match = @($hits | Where-Object { $_.Value -eq $r.Expect })
$ok = $match.Count -gt 0
$detail = if ($hits.Count -eq 0) { "not set in any user hive" }
else { ($hits | ForEach-Object { "$(Split-Path $_.Hive -Leaf)=$($_.Value)" }) -join ', ' }
Check $r.Desc $ok $detail
}
Write-Host ""
Write-Host "===== Summary ====="
Write-Host ("PASS: {0} FAIL: {1}" -f $pass, $fail)

View File

@@ -0,0 +1,91 @@
param(
[switch]$KeepWorkDir
)
[Console]::OutputEncoding = [Text.Encoding]::UTF8
$ErrorActionPreference = 'Stop'
# 1. Must be Windows PowerShell 5.1 (Win11Debloat targets powershell.exe)
if ($PSVersionTable.PSVersion.Major -ge 7) {
throw "Run with powershell.exe 5.1, not pwsh $($PSVersionTable.PSVersion)"
}
# 2. Must have Administrator token
$isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not $isAdmin) { throw "Administrator token required" }
# 3. Config must exist beside this script
$userConfigSrc = Join-Path $PSScriptRoot 'win11debloat-config.json'
if (-not (Test-Path $userConfigSrc)) { throw "Missing $userConfigSrc" }
# 4. Download repo zip to a fresh work dir
$workDir = Join-Path $env:TEMP 'Win11Debloat-run'
if (Test-Path $workDir) { Remove-Item $workDir -Recurse -Force }
New-Item -ItemType Directory -Path $workDir | Out-Null
$zipUrl = 'https://github.com/Raphire/Win11Debloat/archive/refs/heads/master.zip'
$zipPath = Join-Path $workDir 'repo.zip'
Write-Host "[*] Downloading $zipUrl"
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Invoke-WebRequest -Uri $zipUrl -OutFile $zipPath -UseBasicParsing
if ((Get-Item $zipPath).Length -lt 100KB) { throw "Downloaded zip seems too small" }
Expand-Archive -Path $zipPath -DestinationPath $workDir -Force
$repoRoot = Join-Path $workDir 'Win11Debloat-master'
if (-not (Test-Path (Join-Path $repoRoot 'Win11Debloat.ps1'))) {
throw "Win11Debloat.ps1 missing after extract"
}
# 5. Stage our config alongside the repo and BOM-patch all .ps1 files
# (PowerShell 5.1 on zh-TW Windows reads non-BOM files as CP950 → breaks)
$userConfigDst = Join-Path $repoRoot 'my-config.json'
Copy-Item $userConfigSrc $userConfigDst -Force
$psFiles = Get-ChildItem -Path $repoRoot -Recurse -Filter '*.ps1'
$added = 0
foreach ($f in $psFiles) {
$bytes = [IO.File]::ReadAllBytes($f.FullName)
$hasBom = $bytes.Length -ge 3 -and $bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF
if (-not $hasBom) {
$bom = [byte[]](0xEF, 0xBB, 0xBF)
[IO.File]::WriteAllBytes($f.FullName, $bom + $bytes)
$added++
}
}
Write-Host "[*] BOM-patched $added of $($psFiles.Count) .ps1 files"
# 6. Run Win11Debloat
$logPath = Join-Path $repoRoot ("run-$(Get-Date -Format 'yyyyMMdd-HHmmss').log")
$script = Join-Path $repoRoot 'Win11Debloat.ps1'
Write-Host "[*] Running Win11Debloat -Silent -Config my-config.json"
Write-Host "[*] Log -> $logPath"
Write-Host ('-' * 60)
Push-Location $repoRoot
try {
$proc = Start-Process -FilePath 'powershell.exe' -ArgumentList @(
'-NoProfile','-ExecutionPolicy','Bypass','-File', $script,
'-Silent','-Config', $userConfigDst, '-LogPath', $logPath, '-NoRestartExplorer'
) -NoNewWindow -Wait -PassThru
}
finally {
Pop-Location
}
Write-Host ('-' * 60)
if (Test-Path $logPath) {
Write-Host "--- log tail ---"
Get-Content $logPath | Select-Object -Last 100
}
Write-Host ""
Write-Host "[=] Exit code: $($proc.ExitCode)"
Write-Host "[=] Full log: $logPath"
Write-Host "[!] Reboot (or at least restart Explorer) to apply UI changes."
if (-not $KeepWorkDir) {
Write-Host "[*] Cleaning up $workDir (use -KeepWorkDir to keep)"
Remove-Item $workDir -Recurse -Force -ErrorAction SilentlyContinue
}
exit $proc.ExitCode

28
scripts/ssh/activate-windows.sh Executable file
View File

@@ -0,0 +1,28 @@
#!/usr/bin/env bash
set -euo pipefail
HOST="${HOST:-192.168.88.108}"
USER_NAME="${USER_NAME:-Admin}"
PASS="${PASS:-P@ssw0rd!}"
HERE="$(cd "$(dirname "$0")" && pwd)"
SCRIPT="$HERE/../powershell/activate-windows.ps1"
LOG_DIR="$HERE/../../logs"
STAMP="$(date +%Y%m%d-%H%M%S)"
LOG="$LOG_DIR/activate-windows-${HOST}-${STAMP}.log"
mkdir -p "$LOG_DIR"
SSH_OPTS=(-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10)
echo "[*] 上傳 Windows 啟用腳本到 $USER_NAME@$HOST"
sshpass -p "$PASS" scp "${SSH_OPTS[@]}" "$SCRIPT" \
"$USER_NAME@$HOST:C:/Users/$USER_NAME/activate-windows.ps1" >/dev/null
echo "[*] 執行 Windows 啟用程序log -> $LOG"
sshpass -p "$PASS" ssh "${SSH_OPTS[@]}" "$USER_NAME@$HOST" \
"powershell -NoProfile -ExecutionPolicy Bypass -File C:/Users/$USER_NAME/activate-windows.ps1" \
2>&1 | tee "$LOG"
echo ""
echo "[*] 完成。紀錄已儲存: $LOG"

28
scripts/ssh/apply-ui-to-user.sh Executable file
View File

@@ -0,0 +1,28 @@
#!/usr/bin/env bash
set -euo pipefail
HOST="${HOST:-192.168.88.108}"
USER_NAME="${USER_NAME:-Admin}"
PASS="${PASS:-P@ssw0rd!}"
TARGET_USER="${TARGET_USER:-user}"
HERE="$(cd "$(dirname "$0")" && pwd)"
SCRIPT="$HERE/../powershell/apply-ui-to-user.ps1"
LOG_DIR="$HERE/../../logs"
STAMP="$(date +%Y%m%d-%H%M%S)"
LOG="$LOG_DIR/apply-ui-to-user-${HOST}-${TARGET_USER}-${STAMP}.log"
mkdir -p "$LOG_DIR"
SSH_OPTS=(-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10)
echo "[*] Uploading apply-ui-to-user.ps1 to $USER_NAME@$HOST"
sshpass -p "$PASS" scp "${SSH_OPTS[@]}" "$SCRIPT" \
"$USER_NAME@$HOST:C:/Users/$USER_NAME/apply-ui-to-user.ps1" >/dev/null
echo "[*] Applying UI settings to '$TARGET_USER' on $HOST, log -> $LOG"
sshpass -p "$PASS" ssh "${SSH_OPTS[@]}" "$USER_NAME@$HOST" \
"powershell -NoProfile -ExecutionPolicy Bypass -File C:/Users/$USER_NAME/apply-ui-to-user.ps1 -TargetUser $TARGET_USER" \
2>&1 | tee "$LOG"
echo "[*] Done. Saved: $LOG"

36
scripts/ssh/check-winrm.sh Executable file
View File

@@ -0,0 +1,36 @@
#!/usr/bin/env bash
set -euo pipefail
HOST="${HOST:-192.168.88.108}"
USER_NAME="${USER_NAME:-Admin}"
PASS="${PASS:-P@ssw0rd!}"
HERE="$(cd "$(dirname "$0")" && pwd)"
SCRIPT="$HERE/../powershell/check-winrm.ps1"
LOG_DIR="$HERE/../../logs"
STAMP="$(date +%Y%m%d-%H%M%S)"
LOG="$LOG_DIR/check-winrm-${HOST}-${STAMP}.log"
mkdir -p "$LOG_DIR"
SSH_OPTS=(-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10)
echo "[*] Checking WinRM status on $USER_NAME@$HOST"
echo "[*] Uploading WinRM check script..."
sshpass -p "$PASS" scp "${SSH_OPTS[@]}" "$SCRIPT" "$USER_NAME@$HOST:C:/Users/$USER_NAME/check-winrm.ps1" >/dev/null
echo "[*] Running WinRM configuration check, log -> $LOG"
echo "=================================================================="
sshpass -p "$PASS" ssh "${SSH_OPTS[@]}" "$USER_NAME@$HOST" \
"powershell -NoProfile -ExecutionPolicy Bypass -File C:/Users/$USER_NAME/check-winrm.ps1" \
2>&1 | tee "$LOG"
echo "=================================================================="
echo "[*] WinRM check completed. Log saved: $LOG"
echo ""
echo "Next steps based on results:"
echo " ✅ If WinRM is ready -> Create WinRM connection scripts"
echo " ⚠️ If partially ready -> Run enable-winrm.sh to fix configuration"
echo " ❌ If not configured -> Run enable-winrm.sh to set up WinRM"

28
scripts/ssh/configure-ime.sh Executable file
View File

@@ -0,0 +1,28 @@
#!/usr/bin/env bash
set -euo pipefail
HOST="${HOST:-192.168.88.108}"
USER_NAME="${USER_NAME:-Admin}"
PASS="${PASS:-P@ssw0rd!}"
TARGET_USER="${TARGET_USER:-User}"
HERE="$(cd "$(dirname "$0")" && pwd)"
SCRIPT="$HERE/../powershell/configure-ime.ps1"
LOG_DIR="$HERE/../../logs"
STAMP="$(date +%Y%m%d-%H%M%S)"
LOG="$LOG_DIR/configure-ime-${HOST}-${TARGET_USER}-${STAMP}.log"
mkdir -p "$LOG_DIR"
SSH_OPTS=(-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10)
echo "[*] Uploading configure-ime.ps1 to $USER_NAME@$HOST"
sshpass -p "$PASS" scp "${SSH_OPTS[@]}" "$SCRIPT" \
"$USER_NAME@$HOST:C:/Users/$USER_NAME/configure-ime.ps1" >/dev/null
echo "[*] Configuring IME for '$TARGET_USER' on $HOST, log -> $LOG"
sshpass -p "$PASS" ssh "${SSH_OPTS[@]}" "$USER_NAME@$HOST" \
"powershell -NoProfile -ExecutionPolicy Bypass -File C:/Users/$USER_NAME/configure-ime.ps1 -TargetUser $TARGET_USER" \
2>&1 | tee "$LOG"
echo "[*] Done. Saved: $LOG"

View File

@@ -0,0 +1,31 @@
#!/usr/bin/env bash
set -euo pipefail
HOST="${HOST:-pc-74269}"
USER_NAME="${USER_NAME:-Admin}"
PASS="${PASS:-P@ssw0rd!}"
HERE="$(cd "$(dirname "$0")" && pwd)"
SCRIPT="$HERE/../powershell/debug-winrm-network.ps1"
LOG_DIR="$HERE/../../logs"
STAMP="$(date +%Y%m%d-%H%M%S)"
LOG="$LOG_DIR/debug-winrm-network-${HOST}-${STAMP}.log"
mkdir -p "$LOG_DIR"
SSH_OPTS=(-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10)
echo "[*] Debugging WinRM network connectivity on $USER_NAME@$HOST"
echo "[*] Uploading diagnostic script..."
sshpass -p "$PASS" scp "${SSH_OPTS[@]}" "$SCRIPT" "$USER_NAME@$HOST:C:/Users/$USER_NAME/debug-winrm-network.ps1" >/dev/null
echo "[*] Running WinRM network diagnostics, log -> $LOG"
echo "=================================================================="
sshpass -p "$PASS" ssh "${SSH_OPTS[@]}" "$USER_NAME@$HOST" \
"powershell -NoProfile -ExecutionPolicy Bypass -File C:/Users/$USER_NAME/debug-winrm-network.ps1" \
2>&1 | tee "$LOG"
echo "=================================================================="
echo "[*] WinRM network diagnostics completed. Log saved: $LOG"

47
scripts/ssh/enable-winrm.sh Executable file
View File

@@ -0,0 +1,47 @@
#!/usr/bin/env bash
set -euo pipefail
HOST="${HOST:-192.168.88.108}"
USER_NAME="${USER_NAME:-Admin}"
PASS="${PASS:-P@ssw0rd!}"
HERE="$(cd "$(dirname "$0")" && pwd)"
SCRIPT="$HERE/../powershell/enable-winrm.ps1"
LOG_DIR="$HERE/../../logs"
STAMP="$(date +%Y%m%d-%H%M%S)"
LOG="$LOG_DIR/enable-winrm-${HOST}-${STAMP}.log"
mkdir -p "$LOG_DIR"
SSH_OPTS=(-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10)
echo "[*] Enabling WinRM on $USER_NAME@$HOST"
echo "[*] This will configure PowerShell Remoting and WinRM service"
echo ""
echo "⚠️ WARNING: This script will enable Basic authentication and unencrypted"
echo " communication for testing. Consider security implications for production."
echo ""
read -p "Continue? [y/N] " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "Aborted."
exit 1
fi
echo "[*] Uploading WinRM enablement script..."
sshpass -p "$PASS" scp "${SSH_OPTS[@]}" "$SCRIPT" "$USER_NAME@$HOST:C:/Users/$USER_NAME/enable-winrm.ps1" >/dev/null
echo "[*] Running WinRM configuration (requires Administrator), log -> $LOG"
echo "=================================================================="
sshpass -p "$PASS" ssh "${SSH_OPTS[@]}" "$USER_NAME@$HOST" \
"powershell -NoProfile -ExecutionPolicy Bypass -File C:/Users/$USER_NAME/enable-winrm.ps1" \
2>&1 | tee "$LOG"
echo "=================================================================="
echo "[*] WinRM configuration completed. Log saved: $LOG"
echo ""
echo "Next steps:"
echo " 1. Run ./check-winrm.sh to verify configuration"
echo " 2. Test WinRM connection from this machine"
echo " 3. If successful, update existing scripts to use WinRM"

View File

@@ -0,0 +1,27 @@
#!/usr/bin/env bash
set -euo pipefail
HOST="${HOST:-192.168.88.108}"
USER_NAME="${USER_NAME:-Admin}"
PASS="${PASS:-P@ssw0rd!}"
HERE="$(cd "$(dirname "$0")" && pwd)"
SCRIPT="$HERE/../powershell/firewall-allow-ssh.ps1"
LOG_DIR="$HERE/../../logs"
STAMP="$(date +%Y%m%d-%H%M%S)"
LOG="$LOG_DIR/firewall-allow-ssh-${HOST}-${STAMP}.log"
mkdir -p "$LOG_DIR"
SSH_OPTS=(-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10)
echo "[*] Uploading firewall-allow-ssh.ps1 to $USER_NAME@$HOST"
sshpass -p "$PASS" scp "${SSH_OPTS[@]}" "$SCRIPT" \
"$USER_NAME@$HOST:C:/Users/$USER_NAME/firewall-allow-ssh.ps1" >/dev/null
echo "[*] Running on $HOST, log -> $LOG"
sshpass -p "$PASS" ssh "${SSH_OPTS[@]}" "$USER_NAME@$HOST" \
"powershell -NoProfile -ExecutionPolicy Bypass -File C:/Users/$USER_NAME/firewall-allow-ssh.ps1" \
2>&1 | tee "$LOG"
echo "[*] Done. Saved: $LOG"

31
scripts/ssh/fix-winrm.sh Executable file
View File

@@ -0,0 +1,31 @@
#!/usr/bin/env bash
set -euo pipefail
HOST="${HOST:-192.168.88.108}"
USER_NAME="${USER_NAME:-Admin}"
PASS="${PASS:-P@ssw0rd!}"
HERE="$(cd "$(dirname "$0")" && pwd)"
SCRIPT="$HERE/../powershell/fix-winrm.ps1"
LOG_DIR="$HERE/../../logs"
STAMP="$(date +%Y%m%d-%H%M%S)"
LOG="$LOG_DIR/fix-winrm-${HOST}-${STAMP}.log"
mkdir -p "$LOG_DIR"
SSH_OPTS=(-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10)
echo "[*] Fixing remaining WinRM configuration issues on $USER_NAME@$HOST"
echo "[*] Uploading fix script..."
sshpass -p "$PASS" scp "${SSH_OPTS[@]}" "$SCRIPT" "$USER_NAME@$HOST:C:/Users/$USER_NAME/fix-winrm.ps1" >/dev/null
echo "[*] Running WinRM configuration fixes, log -> $LOG"
echo "=================================================================="
sshpass -p "$PASS" ssh "${SSH_OPTS[@]}" "$USER_NAME@$HOST" \
"powershell -NoProfile -ExecutionPolicy Bypass -File C:/Users/$USER_NAME/fix-winrm.ps1" \
2>&1 | tee "$LOG"
echo "=================================================================="
echo "[*] WinRM fixes completed. Log saved: $LOG"

30
scripts/ssh/install-apps.sh Executable file
View File

@@ -0,0 +1,30 @@
#!/usr/bin/env bash
set -euo pipefail
HOST="${HOST:-192.168.88.108}"
USER_NAME="${USER_NAME:-Admin}"
PASS="${PASS:-P@ssw0rd!}"
HERE="$(cd "$(dirname "$0")" && pwd)"
SCRIPT="$HERE/../powershell/install-apps.ps1"
LOG_DIR="$HERE/../../logs"
STAMP="$(date +%Y%m%d-%H%M%S)"
LOG="$LOG_DIR/install-apps-${HOST}-${STAMP}.log"
mkdir -p "$LOG_DIR"
SSH_OPTS=(-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10)
echo "[*] 上傳應用程式安裝腳本到 $USER_NAME@$HOST"
sshpass -p "$PASS" scp "${SSH_OPTS[@]}" "$SCRIPT" \
"$USER_NAME@$HOST:C:/Users/$USER_NAME/install-apps.ps1" >/dev/null
echo "[*] 執行應用程式安裝 (AnyDesk, LINE, Chrome, 7zip, Adobe Reader)"
echo " 這可能需要 5-15 分鐘,依據網路速度而定"
echo " Log -> $LOG"
sshpass -p "$PASS" ssh "${SSH_OPTS[@]}" "$USER_NAME@$HOST" \
"powershell -NoProfile -ExecutionPolicy Bypass -File C:/Users/$USER_NAME/install-apps.ps1" \
2>&1 | tee "$LOG"
echo ""
echo "[*] 安裝完成。紀錄已儲存: $LOG"

27
scripts/ssh/install-cports.sh Executable file
View File

@@ -0,0 +1,27 @@
#!/usr/bin/env bash
set -euo pipefail
HOST="${HOST:-192.168.88.108}"
USER_NAME="${USER_NAME:-Admin}"
PASS="${PASS:-P@ssw0rd!}"
HERE="$(cd "$(dirname "$0")" && pwd)"
SCRIPT="$HERE/../powershell/install-cports.ps1"
LOG_DIR="$HERE/../../logs"
STAMP="$(date +%Y%m%d-%H%M%S)"
LOG="$LOG_DIR/install-cports-${HOST}-${STAMP}.log"
mkdir -p "$LOG_DIR"
SSH_OPTS=(-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10)
echo "[*] Uploading install-cports.ps1 to $USER_NAME@$HOST"
sshpass -p "$PASS" scp "${SSH_OPTS[@]}" "$SCRIPT" \
"$USER_NAME@$HOST:C:/Users/$USER_NAME/install-cports.ps1" >/dev/null
echo "[*] Running on $HOST, log -> $LOG"
sshpass -p "$PASS" ssh "${SSH_OPTS[@]}" "$USER_NAME@$HOST" \
"powershell -NoProfile -ExecutionPolicy Bypass -File C:/Users/$USER_NAME/install-cports.ps1" \
2>&1 | tee "$LOG"
echo "[*] Done. Saved: $LOG"

29
scripts/ssh/install-nirsoft.sh Executable file
View File

@@ -0,0 +1,29 @@
#!/usr/bin/env bash
set -euo pipefail
HOST="${HOST:-192.168.88.108}"
USER_NAME="${USER_NAME:-Admin}"
PASS="${PASS:-P@ssw0rd!}"
HERE="$(cd "$(dirname "$0")" && pwd)"
SCRIPT="$HERE/../powershell/install-nirsoft.ps1"
CONFIG="$HERE/nirsoft-config.json"
LOG_DIR="$HERE/../../logs"
STAMP="$(date +%Y%m%d-%H%M%S)"
LOG="$LOG_DIR/install-nirsoft-${HOST}-${STAMP}.log"
mkdir -p "$LOG_DIR"
SSH_OPTS=(-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10 -o ServerAliveInterval=30)
echo "[*] Uploading install-nirsoft.ps1 and nirsoft-config.json"
sshpass -p "$PASS" scp "${SSH_OPTS[@]}" "$SCRIPT" "$CONFIG" \
"$USER_NAME@$HOST:C:/Users/$USER_NAME/" >/dev/null
echo "[*] Running on $HOST — this downloads ~16 archives, may take a few minutes"
echo "[*] Log -> $LOG"
sshpass -p "$PASS" ssh "${SSH_OPTS[@]}" "$USER_NAME@$HOST" \
"powershell -NoProfile -ExecutionPolicy Bypass -File C:/Users/$USER_NAME/install-nirsoft.ps1" \
2>&1 | tee "$LOG"
echo "[*] Done. Saved: $LOG"

27
scripts/ssh/install-telegram.sh Executable file
View File

@@ -0,0 +1,27 @@
#!/usr/bin/env bash
set -euo pipefail
HOST="${HOST:-192.168.88.108}"
USER_NAME="${USER_NAME:-Admin}"
PASS="${PASS:-P@ssw0rd!}"
HERE="$(cd "$(dirname "$0")" && pwd)"
SCRIPT="$HERE/../powershell/install-telegram.ps1"
LOG_DIR="$HERE/../../logs"
STAMP="$(date +%Y%m%d-%H%M%S)"
LOG="$LOG_DIR/install-telegram-${HOST}-${STAMP}.log"
mkdir -p "$LOG_DIR"
SSH_OPTS=(-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10)
echo "[*] Uploading install-telegram.ps1 to $USER_NAME@$HOST"
sshpass -p "$PASS" scp "${SSH_OPTS[@]}" "$SCRIPT" \
"$USER_NAME@$HOST:C:/Users/$USER_NAME/install-telegram.ps1" >/dev/null
echo "[*] Running installer on $HOST, log -> $LOG"
sshpass -p "$PASS" ssh "${SSH_OPTS[@]}" "$USER_NAME@$HOST" \
"powershell -NoProfile -ExecutionPolicy Bypass -File C:/Users/$USER_NAME/install-telegram.ps1" \
2>&1 | tee "$LOG"
echo "[*] Done. Saved: $LOG"

View File

@@ -0,0 +1,27 @@
#!/usr/bin/env bash
set -euo pipefail
HOST="${HOST:-192.168.88.108}"
USER_NAME="${USER_NAME:-Admin}"
PASS="${PASS:-P@ssw0rd!}"
HERE="$(cd "$(dirname "$0")" && pwd)"
SCRIPT="$HERE/../powershell/install-thunderbird.ps1"
LOG_DIR="$HERE/../../logs"
STAMP="$(date +%Y%m%d-%H%M%S)"
LOG="$LOG_DIR/install-thunderbird-${HOST}-${STAMP}.log"
mkdir -p "$LOG_DIR"
SSH_OPTS=(-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10)
echo "[*] Uploading install-thunderbird.ps1 to $USER_NAME@$HOST"
sshpass -p "$PASS" scp "${SSH_OPTS[@]}" "$SCRIPT" \
"$USER_NAME@$HOST:C:/Users/$USER_NAME/install-thunderbird.ps1" >/dev/null
echo "[*] Running installer on $HOST, log -> $LOG"
sshpass -p "$PASS" ssh "${SSH_OPTS[@]}" "$USER_NAME@$HOST" \
"powershell -NoProfile -ExecutionPolicy Bypass -File C:/Users/$USER_NAME/install-thunderbird.ps1" \
2>&1 | tee "$LOG"
echo "[*] Done. Saved: $LOG"

52
scripts/ssh/nirsoft-dump.sh Executable file
View File

@@ -0,0 +1,52 @@
#!/usr/bin/env bash
set -euo pipefail
HOST="${HOST:-192.168.88.108}"
USER_NAME="${USER_NAME:-Admin}"
PASS="${PASS:-P@ssw0rd!}"
HERE="$(cd "$(dirname "$0")" && pwd)"
SCRIPT="$HERE/../powershell/nirsoft-dump.ps1"
DUMP_DIR="$HERE/dumps"
LOG_DIR="$HERE/../../logs"
STAMP="$(date +%Y%m%d-%H%M%S)"
LOG="$LOG_DIR/nirsoft-dump-${HOST}-${STAMP}.log"
mkdir -p "$DUMP_DIR" "$LOG_DIR"
SSH_OPTS=(-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10)
echo "[*] Uploading nirsoft-dump.ps1 to $USER_NAME@$HOST"
sshpass -p "$PASS" scp "${SSH_OPTS[@]}" "$SCRIPT" \
"$USER_NAME@$HOST:C:/Users/$USER_NAME/nirsoft-dump.ps1" >/dev/null
echo "[*] Running dump on $HOST (this takes ~1-2 min), log -> $LOG"
OUT=$(sshpass -p "$PASS" ssh "${SSH_OPTS[@]}" "$USER_NAME@$HOST" \
"powershell -NoProfile -ExecutionPolicy Bypass -File C:/Users/$USER_NAME/nirsoft-dump.ps1" \
2>&1 | tee "$LOG")
REMOTE_ZIP=$(echo "$OUT" | grep '^DUMP_ZIP:' | awk '{print $2}' | tr -d '\r')
REMOTE_SIZE=$(echo "$OUT" | grep '^DUMP_SIZE:' | awk '{print $2}' | tr -d '\r')
if [[ -z "$REMOTE_ZIP" ]]; then
echo "[!] Could not find DUMP_ZIP line in output" >&2
exit 1
fi
# Convert Windows path to forward-slash form for scp + basename
REMOTE_ZIP_SCP=$(echo "$REMOTE_ZIP" | sed 's|\\|/|g')
LOCAL_ZIP="$DUMP_DIR/$(basename "$REMOTE_ZIP_SCP")"
echo ""
echo "[*] Pulling zip back: $REMOTE_ZIP_SCP (${REMOTE_SIZE} bytes) -> $LOCAL_ZIP"
sshpass -p "$PASS" scp "${SSH_OPTS[@]}" \
"$USER_NAME@$HOST:$REMOTE_ZIP_SCP" "$LOCAL_ZIP" >/dev/null
# Clean up remote copy
sshpass -p "$PASS" ssh "${SSH_OPTS[@]}" "$USER_NAME@$HOST" \
"del \"$REMOTE_ZIP\"" >/dev/null 2>&1 || true
echo ""
echo "[OK] Dump saved: $LOCAL_ZIP"
echo " Unzip with: unzip -l \"$LOCAL_ZIP\" (to list)"
echo " unzip \"$LOCAL_ZIP\" -d \"${LOCAL_ZIP%.zip}/\" (to extract)"

26
scripts/ssh/recon.sh Executable file
View File

@@ -0,0 +1,26 @@
#!/usr/bin/env bash
set -euo pipefail
HOST="${HOST:-192.168.88.108}"
USER_NAME="${USER_NAME:-Admin}"
PASS="${PASS:-P@ssw0rd!}"
HERE="$(cd "$(dirname "$0")" && pwd)"
SCRIPT="$HERE/../powershell/recon.ps1"
LOG_DIR="$HERE/../../logs"
STAMP="$(date +%Y%m%d-%H%M%S)"
LOG="$LOG_DIR/recon-${HOST}-${STAMP}.log"
mkdir -p "$LOG_DIR"
SSH_OPTS=(-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10)
echo "[*] Uploading recon.ps1 to $USER_NAME@$HOST"
sshpass -p "$PASS" scp "${SSH_OPTS[@]}" "$SCRIPT" "$USER_NAME@$HOST:C:/Users/$USER_NAME/recon.ps1" >/dev/null
echo "[*] Running recon on $HOST, log -> $LOG"
sshpass -p "$PASS" ssh "${SSH_OPTS[@]}" "$USER_NAME@$HOST" \
"powershell -NoProfile -ExecutionPolicy Bypass -File C:/Users/$USER_NAME/recon.ps1" \
2>&1 | tee "$LOG"
echo "[*] Done. Saved: $LOG"

28
scripts/ssh/remove-apps.sh Executable file
View File

@@ -0,0 +1,28 @@
#!/usr/bin/env bash
set -euo pipefail
HOST="${HOST:-192.168.88.108}"
USER_NAME="${USER_NAME:-Admin}"
PASS="${PASS:-P@ssw0rd!}"
HERE="$(cd "$(dirname "$0")" && pwd)"
SCRIPT="$HERE/../powershell/remove-apps.ps1"
CONFIG="$HERE/remove-apps-config.json"
LOG_DIR="$HERE/../../logs"
STAMP="$(date +%Y%m%d-%H%M%S)"
LOG="$LOG_DIR/remove-apps-${HOST}-${STAMP}.log"
mkdir -p "$LOG_DIR"
SSH_OPTS=(-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10)
echo "[*] Uploading remove-apps.ps1 and remove-apps-config.json"
sshpass -p "$PASS" scp "${SSH_OPTS[@]}" "$SCRIPT" "$CONFIG" \
"$USER_NAME@$HOST:C:/Users/$USER_NAME/" >/dev/null
echo "[*] Running on $HOST, log -> $LOG"
sshpass -p "$PASS" ssh "${SSH_OPTS[@]}" "$USER_NAME@$HOST" \
"powershell -NoProfile -ExecutionPolicy Bypass -File C:/Users/$USER_NAME/remove-apps.ps1" \
2>&1 | tee "$LOG"
echo "[*] Done. Saved: $LOG"

View File

@@ -0,0 +1,33 @@
#!/usr/bin/env bash
set -euo pipefail
HOST="${HOST:-192.168.88.108}"
USER_NAME="${USER_NAME:-Admin}"
PASS="${PASS:-P@ssw0rd!}"
MODE="${MODE:-Apply}" # Apply | Revert
HERE="$(cd "$(dirname "$0")" && pwd)"
SCRIPT="$HERE/../powershell/remove-windows-ai.ps1"
LOG_DIR="$HERE/../../logs"
STAMP="$(date +%Y%m%d-%H%M%S)"
LOG="$LOG_DIR/remove-windows-ai-${HOST}-${MODE}-${STAMP}.log"
mkdir -p "$LOG_DIR"
SSH_OPTS=(-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10 -o ServerAliveInterval=30)
echo "[*] Uploading remove-windows-ai.ps1 to $USER_NAME@$HOST"
sshpass -p "$PASS" scp "${SSH_OPTS[@]}" "$SCRIPT" \
"$USER_NAME@$HOST:C:/Users/$USER_NAME/remove-windows-ai.ps1" >/dev/null
echo "[*] Mode=$MODE. Running on $HOST — this can take several minutes"
echo "[*] Log -> $LOG"
# Force Windows PowerShell 5.1 (powershell.exe), not pwsh 7.
sshpass -p "$PASS" ssh "${SSH_OPTS[@]}" "$USER_NAME@$HOST" \
"powershell.exe -NoProfile -ExecutionPolicy Bypass -File C:/Users/$USER_NAME/remove-windows-ai.ps1 -Mode $MODE" \
2>&1 | tee "$LOG"
echo "[*] Done. Saved: $LOG"
echo ""
echo "NOTE: A reboot is recommended. Reboot with:"
echo " sshpass -p '$PASS' ssh $USER_NAME@$HOST 'shutdown /r /t 5'"

View File

@@ -0,0 +1,27 @@
#!/usr/bin/env bash
set -euo pipefail
HOST="${HOST:-192.168.88.108}"
USER_NAME="${USER_NAME:-Admin}"
PASS="${PASS:-P@ssw0rd!}"
HERE="$(cd "$(dirname "$0")" && pwd)"
SCRIPT="$HERE/../powershell/rename-hide-accounts.ps1"
LOG_DIR="$HERE/../../logs"
STAMP="$(date +%Y%m%d-%H%M%S)"
LOG="$LOG_DIR/rename-hide-accounts-${HOST}-${STAMP}.log"
mkdir -p "$LOG_DIR"
SSH_OPTS=(-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10)
echo "[*] Uploading rename-hide-accounts.ps1 to $USER_NAME@$HOST"
sshpass -p "$PASS" scp "${SSH_OPTS[@]}" "$SCRIPT" \
"$USER_NAME@$HOST:C:/Users/$USER_NAME/rename-hide-accounts.ps1" >/dev/null
echo "[*] Running on $HOST, log -> $LOG"
sshpass -p "$PASS" ssh "${SSH_OPTS[@]}" "$USER_NAME@$HOST" \
"powershell -NoProfile -ExecutionPolicy Bypass -File C:/Users/$USER_NAME/rename-hide-accounts.ps1" \
2>&1 | tee "$LOG"
echo "[*] Done. Saved: $LOG"

View File

@@ -0,0 +1,33 @@
#!/usr/bin/env bash
set -euo pipefail
HOST="${HOST:-192.168.88.108}"
USER_NAME="${USER_NAME:-Admin}"
PASS="${PASS:-P@ssw0rd!}"
HERE="$(cd "$(dirname "$0")" && pwd)"
SCRIPT="$HERE/../powershell/setup-thunderbird.ps1"
CONFIG="$HERE/thunderbird-config.json"
LOG_DIR="$HERE/../../logs"
STAMP="$(date +%Y%m%d-%H%M%S)"
LOG="$LOG_DIR/setup-thunderbird-${HOST}-${STAMP}.log"
mkdir -p "$LOG_DIR"
SSH_OPTS=(-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10)
if [[ ! -f "$CONFIG" ]]; then
echo "[!] Missing $CONFIG — please edit thunderbird-config.json first" >&2
exit 1
fi
echo "[*] Uploading setup-thunderbird.ps1 and thunderbird-config.json"
sshpass -p "$PASS" scp "${SSH_OPTS[@]}" "$SCRIPT" "$CONFIG" \
"$USER_NAME@$HOST:C:/Users/$USER_NAME/" >/dev/null
echo "[*] Running setup on $HOST, log -> $LOG"
sshpass -p "$PASS" ssh "${SSH_OPTS[@]}" "$USER_NAME@$HOST" \
"powershell -NoProfile -ExecutionPolicy Bypass -File C:/Users/$USER_NAME/setup-thunderbird.ps1" \
2>&1 | tee "$LOG"
echo "[*] Done. Saved: $LOG"

View File

@@ -0,0 +1,99 @@
#!/usr/bin/env bash
set -euo pipefail
HOST="${HOST:-192.168.88.108}"
USER_NAME="${USER_NAME:-Admin}"
PASS="${PASS:-P@ssw0rd!}"
echo "=== Testing WinRM Connection to $HOST ==="
echo ""
# Test 1: Check if PowerShell Core is installed
echo "[1/4] Checking PowerShell Core availability..."
if command -v pwsh >/dev/null 2>&1; then
echo "✅ PowerShell Core found: $(pwsh --version)"
else
echo "❌ PowerShell Core not found"
echo "Install with: brew install powershell"
exit 1
fi
# Test 2: Test basic network connectivity to WinRM port
echo ""
echo "[2/4] Testing network connectivity to WinRM port 5985..."
if nc -z "$HOST" 5985; then
echo "✅ Port 5985 is reachable"
else
echo "❌ Cannot reach port 5985 on $HOST"
exit 1
fi
# Test 3: Test HTTP WinRM endpoint with curl
echo ""
echo "[3/4] Testing WinRM HTTP endpoint..."
WINRM_RESPONSE=$(curl -s -w "%{http_code}" -o /dev/null --max-time 10 \
"http://$HOST:5985/wsman" \
-H "Content-Type: application/soap+xml;charset=UTF-8" \
-H "SOAPAction: http://schemas.xmlsoap.org/ws/2004/09/enumeration/Enumerate" \
--data '<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"><soap:Header/><soap:Body><wsen:Enumerate xmlns:wsen="http://schemas.xmlsoap.org/ws/2004/09/enumeration"><wsen:Filter xmlns:wsman="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd">SELECT * FROM Win32_Service</wsen:Filter></wsen:Enumerate></soap:Body></soap:Envelope>' 2>/dev/null || echo "000")
if [ "$WINRM_RESPONSE" = "401" ]; then
echo "✅ WinRM endpoint responding (401 = authentication required, expected)"
elif [ "$WINRM_RESPONSE" = "500" ]; then
echo "✅ WinRM endpoint responding (500 = server error, but WinRM is there)"
else
echo "⚠️ WinRM endpoint response: $WINRM_RESPONSE (may still work with PowerShell)"
fi
# Test 4: Test PowerShell remoting
echo ""
echo "[4/4] Testing PowerShell remoting session..."
pwsh -c "
try {
\$secpass = ConvertTo-SecureString '$PASS' -AsPlainText -Force
\$cred = New-Object System.Management.Automation.PSCredential('$USER_NAME', \$secpass)
Write-Host 'Attempting to create PowerShell session...'
\$sessionOption = New-PSSessionOption -SkipCACheck -SkipCNCheck
\$session = New-PSSession -ComputerName '$HOST' -Port 5985 -Credential \$cred -UseSSL:\$false -SessionOption \$sessionOption -ErrorAction Stop
Write-Host '✅ PowerShell remoting session created successfully'
# Test running a simple command
\$result = Invoke-Command -Session \$session -ScriptBlock {
@{
ComputerName = \$env:COMPUTERNAME
UserName = \$env:USERNAME
PSVersion = \$PSVersionTable.PSVersion.ToString()
CurrentTime = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
}
}
Write-Host 'Remote session info:'
Write-Host ' Computer:' \$result.ComputerName
Write-Host ' User:' \$result.UserName
Write-Host ' PowerShell:' \$result.PSVersion
Write-Host ' Time:' \$result.CurrentTime
Remove-PSSession \$session
Write-Host '✅ Session closed successfully'
} catch {
Write-Host '❌ PowerShell remoting failed:' \$_.Exception.Message
Write-Host ''
Write-Host 'Common causes:'
Write-Host ' - AllowUnencrypted=false (current setting on target)'
Write-Host ' - Firewall blocking connections'
Write-Host ' - Network connectivity issues'
Write-Host ' - Authentication problems'
exit 1
}
"
echo ""
echo "🎉 All WinRM connectivity tests passed!"
echo ""
echo "WinRM is ready for use. You can now:"
echo " 1. Create WinRM-based versions of existing scripts"
echo " 2. Use PowerShell remoting for direct command execution"
echo " 3. Compare performance with SSH-based approach"

View File

@@ -0,0 +1,27 @@
#!/usr/bin/env bash
set -euo pipefail
HOST="${HOST:-192.168.88.108}"
USER_NAME="${USER_NAME:-Admin}"
PASS="${PASS:-P@ssw0rd!}"
HERE="$(cd "$(dirname "$0")" && pwd)"
SCRIPT="$HERE/../powershell/verify-ai-removed.ps1"
LOG_DIR="$HERE/../../logs"
STAMP="$(date +%Y%m%d-%H%M%S)"
LOG="$LOG_DIR/verify-ai-removed-${HOST}-${STAMP}.log"
mkdir -p "$LOG_DIR"
SSH_OPTS=(-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10)
echo "[*] Uploading verify-ai-removed.ps1 to $USER_NAME@$HOST"
sshpass -p "$PASS" scp "${SSH_OPTS[@]}" "$SCRIPT" \
"$USER_NAME@$HOST:C:/Users/$USER_NAME/verify-ai-removed.ps1" >/dev/null
echo "[*] Running verify on $HOST, log -> $LOG"
sshpass -p "$PASS" ssh "${SSH_OPTS[@]}" "$USER_NAME@$HOST" \
"powershell -NoProfile -ExecutionPolicy Bypass -File C:/Users/$USER_NAME/verify-ai-removed.ps1" \
2>&1 | tee "$LOG"
echo "[*] Done. Saved: $LOG"

27
scripts/ssh/verify-debloat.sh Executable file
View File

@@ -0,0 +1,27 @@
#!/usr/bin/env bash
set -euo pipefail
HOST="${HOST:-192.168.88.108}"
USER_NAME="${USER_NAME:-Admin}"
PASS="${PASS:-P@ssw0rd!}"
HERE="$(cd "$(dirname "$0")" && pwd)"
SCRIPT="$HERE/../powershell/verify-debloat.ps1"
LOG_DIR="$HERE/../../logs"
STAMP="$(date +%Y%m%d-%H%M%S)"
LOG="$LOG_DIR/verify-debloat-${HOST}-${STAMP}.log"
mkdir -p "$LOG_DIR"
SSH_OPTS=(-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10)
echo "[*] Uploading verify-debloat.ps1 to $USER_NAME@$HOST"
sshpass -p "$PASS" scp "${SSH_OPTS[@]}" "$SCRIPT" \
"$USER_NAME@$HOST:C:/Users/$USER_NAME/verify-debloat.ps1" >/dev/null
echo "[*] Running verify on $HOST, log -> $LOG"
sshpass -p "$PASS" ssh "${SSH_OPTS[@]}" "$USER_NAME@$HOST" \
"powershell -NoProfile -ExecutionPolicy Bypass -File C:/Users/$USER_NAME/verify-debloat.ps1" \
2>&1 | tee "$LOG"
echo "[*] Done. Saved: $LOG"

34
scripts/ssh/win11debloat.sh Executable file
View File

@@ -0,0 +1,34 @@
#!/usr/bin/env bash
set -euo pipefail
HOST="${HOST:-192.168.88.108}"
USER_NAME="${USER_NAME:-Admin}"
PASS="${PASS:-P@ssw0rd!}"
HERE="$(cd "$(dirname "$0")" && pwd)"
SCRIPT="$HERE/../powershell/win11debloat.ps1"
CONFIG="$HERE/win11debloat-config.json"
LOG_DIR="$HERE/../../logs"
STAMP="$(date +%Y%m%d-%H%M%S)"
LOG="$LOG_DIR/win11debloat-${HOST}-${STAMP}.log"
mkdir -p "$LOG_DIR"
SSH_OPTS=(-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10 -o ServerAliveInterval=30)
if [[ ! -f "$CONFIG" ]]; then
echo "[!] $CONFIG missing" >&2
exit 1
fi
echo "[*] Uploading win11debloat.ps1 and win11debloat-config.json"
sshpass -p "$PASS" scp "${SSH_OPTS[@]}" "$SCRIPT" "$CONFIG" \
"$USER_NAME@$HOST:C:/Users/$USER_NAME/" >/dev/null
echo "[*] Running on $HOST — this may take several minutes"
echo "[*] Log -> $LOG"
sshpass -p "$PASS" ssh "${SSH_OPTS[@]}" "$USER_NAME@$HOST" \
"powershell.exe -NoProfile -ExecutionPolicy Bypass -File C:/Users/$USER_NAME/win11debloat.ps1" \
2>&1 | tee "$LOG"
echo "[*] Done. Saved: $LOG"

View File

@@ -0,0 +1,174 @@
#!/usr/bin/env python3
"""
Benchmark SSH vs WinRM performance
Compares execution times and capabilities
"""
import time
import subprocess
import os
from winrm import Session
def benchmark_ssh_method():
"""Benchmark SSH-based script execution"""
print("=== SSH Method Benchmark ===")
start_time = time.time()
try:
# Run a simple recon via SSH
result = subprocess.run(
['timeout', '30', './recon.sh'],
capture_output=True,
text=True,
timeout=35
)
end_time = time.time()
duration = end_time - start_time
if result.returncode == 0:
print(f"✅ SSH method successful")
print(f"⏱️ Execution time: {duration:.2f} seconds")
return duration, True
else:
print(f"❌ SSH method failed: {result.stderr}")
return duration, False
except subprocess.TimeoutExpired:
print(f"❌ SSH method timed out after 35 seconds")
return 35, False
except Exception as e:
end_time = time.time()
duration = end_time - start_time
print(f"❌ SSH method error: {e}")
return duration, False
def benchmark_winrm_method():
"""Benchmark WinRM-based script execution"""
print("\n=== WinRM Method Benchmark ===")
host = os.getenv('HOST', '192.168.88.108')
username = os.getenv('USER_NAME', 'Admin')
password = os.getenv('PASS', 'P@ssw0rd!')
start_time = time.time()
try:
# Connect to WinRM
session = Session(
f'http://{host}:5985/wsman',
auth=(username, password),
transport='ntlm'
)
# Run equivalent recon commands via WinRM
recon_script = """
Write-Host ""
Write-Host "======== Computer ========"
Get-ComputerInfo -Property CsName,WindowsProductName,OsVersion,OsInstallDate | Format-List
Write-Host "======== Boot Time ========"
(Get-CimInstance Win32_OperatingSystem).LastBootUpTime
Write-Host "======== Local Users ========"
Get-LocalUser | Select-Object Name,Enabled,LastLogon | Format-Table -AutoSize
Write-Host "======== Disks ========"
Get-Volume | Where-Object DriveLetter | Select-Object DriveLetter,FileSystemLabel,
@{n='Size(GB)';e={[math]::Round($_.Size / 1GB, 1)}},
@{n='Free(GB)';e={[math]::Round($_.SizeRemaining / 1GB, 1)}} | Format-Table -AutoSize
Write-Host "======== IPv4 Addresses ========"
Get-NetIPAddress -AddressFamily IPv4 | Where-Object { $_.InterfaceAlias -notmatch 'Loopback' } |
Select-Object InterfaceAlias,IPAddress | Format-Table -AutoSize
Write-Host "======== WinRM Recon Completed ========"
"""
result = session.run_ps(recon_script)
end_time = time.time()
duration = end_time - start_time
if result.status_code == 0:
print(f"✅ WinRM method successful")
print(f"⏱️ Execution time: {duration:.2f} seconds")
# Show some output
output = result.std_out.decode('utf-8', errors='replace')
lines = [line.strip() for line in output.split('\n') if line.strip()]
print(f"📊 Output lines: {len(lines)}")
return duration, True
else:
print(f"❌ WinRM method failed: {result.std_err.decode()}")
return duration, False
except Exception as e:
end_time = time.time()
duration = end_time - start_time
print(f"❌ WinRM method error: {e}")
return duration, False
def main():
print("🚀 SSH vs WinRM Performance Benchmark")
print("=====================================")
# Benchmark SSH
ssh_time, ssh_success = benchmark_ssh_method()
# Benchmark WinRM
winrm_time, winrm_success = benchmark_winrm_method()
# Results comparison
print("\n📊 RESULTS COMPARISON")
print("=====================")
print(f"SSH Method: {ssh_time:.2f}s {'' if ssh_success else ''}")
print(f"WinRM Method: {winrm_time:.2f}s {'' if winrm_success else ''}")
if ssh_success and winrm_success:
if ssh_time < winrm_time:
speedup = winrm_time / ssh_time
print(f"\n🏃 SSH is {speedup:.1f}x faster than WinRM")
else:
speedup = ssh_time / winrm_time
print(f"\n🏃 WinRM is {speedup:.1f}x faster than SSH")
print(f"\nTime difference: {abs(ssh_time - winrm_time):.2f} seconds")
print("\n🎯 RECOMMENDATION")
print("=================")
if ssh_success and winrm_success:
if ssh_time < winrm_time * 1.5: # If SSH is not significantly slower
print("✅ Continue using SSH method:")
print(" - Proven stability")
print(" - Good performance")
print(" - Handles large scripts well")
print(" - Simpler setup")
else:
print("✅ Consider WinRM method for:")
print(" - Better Windows integration")
print(" - Advanced PowerShell features")
print(" - Structured error handling")
elif ssh_success:
print("✅ SSH method is more reliable for this environment")
elif winrm_success:
print("✅ WinRM method works, SSH has issues")
else:
print("❌ Both methods have issues, investigate connectivity")
print("\n💡 HYBRID APPROACH")
print("==================")
print("Consider using both methods strategically:")
print("- SSH: Large scripts, file operations, stability")
print("- WinRM: Quick commands, Windows-specific tasks, real-time interaction")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,154 @@
#!/usr/bin/env python3
"""
Generate WinRM wrapper scripts for existing PowerShell scripts
Creates Python WinRM alternatives to SSH-based scripts
"""
import os
import sys
from pathlib import Path
import json
def create_winrm_wrapper(ps_script_name, description=""):
"""Create a Python WinRM wrapper for a PowerShell script"""
script_name_base = ps_script_name.replace('.ps1', '')
wrapper_name = f"{script_name_base}-winrm.py"
template = f'''#!/usr/bin/env python3
"""
WinRM version of {ps_script_name}
{description}
"""
import os
import sys
from winrm_executor import WinRMExecutor
from pathlib import Path
def main():
# Get connection details
host = os.getenv('HOST', '192.168.88.108')
username = os.getenv('USER_NAME', 'Admin')
password = os.getenv('PASS', 'P@ssw0rd!')
print(f"=== WinRM Execution: {{username}}@{{host}} - {ps_script_name} ===")
# Create WinRM executor
executor = WinRMExecutor(host, username, password)
try:
# Test connection
print("[*] Establishing WinRM connection...")
if not executor.connect():
print("❌ Failed to establish WinRM connection")
print("\\nTroubleshooting:")
print(" 1. Ensure target machine is powered on and reachable")
print(" 2. Verify WinRM service is running")
print(" 3. Check firewall and network connectivity")
sys.exit(1)
print("✅ WinRM connection established")
# Execute PowerShell script
script_path = Path(__file__).parent / "{ps_script_name}"
if not script_path.exists():
print(f"❌ PowerShell script not found: {{script_path}}")
sys.exit(1)
print(f"[*] Executing {ps_script_name} via WinRM...")
print("=" * 60)
success = executor.upload_and_execute_script(script_path)
print("=" * 60)
if success:
print(f"🎉 {{script_path.name}} completed successfully via WinRM!")
else:
print(f"{{script_path.name}} failed")
sys.exit(1)
finally:
executor.close()
if __name__ == "__main__":
main()
'''
return wrapper_name, template
def main():
current_dir = Path(__file__).parent
# List of PowerShell scripts and their descriptions
scripts = {
'recon.ps1': 'System reconnaissance and inventory',
'activate-windows.ps1': 'Activate Windows using KMS method',
'remove-windows-ai.ps1': 'Remove Windows AI components',
'win11debloat.ps1': 'Remove Windows bloatware and disable telemetry',
'verify-ai-removed.ps1': 'Verify Windows AI removal',
'verify-debloat.ps1': 'Verify Windows debloating changes',
'install-thunderbird.ps1': 'Install Thunderbird email client',
'setup-thunderbird.ps1': 'Configure Thunderbird IMAP/SMTP',
'install-telegram.ps1': 'Install Telegram Desktop',
'install-nirsoft.ps1': 'Install NirSoft diagnostic tools',
'nirsoft-dump.ps1': 'Collect system diagnostic data',
'firewall-allow-ssh.ps1': 'Configure firewall for SSH access',
'apply-ui-to-user.ps1': 'Apply UI settings to user',
'configure-ime.ps1': 'Configure input method settings',
'rename-hide-accounts.ps1': 'Rename and hide user accounts',
'install-cports.ps1': 'Install CurrPorts network tool',
'remove-apps.ps1': 'Remove specified applications'
}
print("=== Generating WinRM Wrapper Scripts ===")
print()
created_count = 0
for ps_script, description in scripts.items():
ps_path = current_dir / ps_script
if ps_path.exists():
wrapper_name, wrapper_content = create_winrm_wrapper(ps_script, description)
wrapper_path = current_dir / wrapper_name
# Only create if it doesn't exist or user confirms overwrite
if wrapper_path.exists():
response = input(f"⚠️ {wrapper_name} exists. Overwrite? [y/N]: ")
if response.lower() != 'y':
print(f"⏭️ Skipping {wrapper_name}")
continue
with open(wrapper_path, 'w', encoding='utf-8') as f:
f.write(wrapper_content)
# Make executable
wrapper_path.chmod(0o755)
print(f"✅ Created: {wrapper_name}")
created_count += 1
else:
print(f"⚠️ PowerShell script not found: {ps_script}")
print()
print(f"🎉 Generated {created_count} WinRM wrapper scripts")
print()
print("Usage examples:")
print(" python3 recon-winrm.py")
print(" HOST=pc-74269 python3 install-thunderbird-winrm.py")
print(" USER_NAME=SomeUser python3 apply-ui-to-user-winrm.py")
print()
print("Benefits of WinRM approach:")
print(" ✅ Native Windows remote management")
print(" ✅ Better PowerShell integration")
print(" ✅ Structured error handling")
print(" ✅ Automatic UTF-8 BOM handling for Chinese Windows")
print(" ✅ Detailed logging and progress reporting")
if __name__ == "__main__":
main()

61
scripts/winrm/recon-winrm.py Executable file
View File

@@ -0,0 +1,61 @@
#!/usr/bin/env python3
"""
WinRM version of recon script
Demonstrates how to replace SSH-based scripts with Python WinRM
"""
import os
import sys
from winrm_executor import WinRMExecutor
from pathlib import Path
def main():
# Get connection details
host = os.getenv('HOST', '192.168.88.108')
username = os.getenv('USER_NAME', 'Admin')
password = os.getenv('PASS', 'P@ssw0rd!')
print(f"=== WinRM Reconnaissance: {username}@{host} ===")
# Create WinRM executor
executor = WinRMExecutor(host, username, password)
try:
# Test connection
print("[*] Establishing WinRM connection...")
if not executor.connect():
print("❌ Failed to establish WinRM connection")
print("\nTroubleshooting:")
print(" 1. Ensure target machine is powered on and reachable")
print(" 2. Verify WinRM service is running: Get-Service WinRM")
print(" 3. Check AllowUnencrypted setting: winrm get winrm/config/service")
print(" 4. Verify firewall rules: Get-NetFirewallRule -DisplayGroup '*Remote Management*'")
sys.exit(1)
print("✅ WinRM connection established")
# Execute recon script
script_path = Path(__file__).parent / "../powershell/recon.ps1"
if not script_path.exists():
print(f"❌ PowerShell script not found: {script_path}")
sys.exit(1)
print(f"[*] Executing reconnaissance script via WinRM...")
print("=" * 60)
success = executor.upload_and_execute_script(script_path)
print("=" * 60)
if success:
print("🎉 Reconnaissance completed successfully via WinRM!")
else:
print("❌ Reconnaissance failed")
sys.exit(1)
finally:
executor.close()
if __name__ == "__main__":
main()

172
scripts/winrm/smart_executor.py Executable file
View File

@@ -0,0 +1,172 @@
#!/usr/bin/env python3
"""
Smart Executor - Automatically choose between SSH and WinRM
Based on script size and complexity
"""
import os
import sys
import subprocess
from pathlib import Path
from winrm import Session
class SmartExecutor:
def __init__(self, host=None, username=None, password=None):
self.host = host or os.getenv('HOST', '192.168.88.108')
self.username = username or os.getenv('USER_NAME', 'Admin')
self.password = password or os.getenv('PASS', 'P@ssw0rd!')
def analyze_script(self, script_path):
"""Analyze script to determine best execution method"""
script_path = Path(script_path)
if not script_path.exists():
return None
# Get script size
size = script_path.stat().st_size
# Read content for analysis
with open(script_path, 'r', encoding='utf-8') as f:
content = f.read()
lines = len(content.split('\n'))
chars = len(content)
analysis = {
'size_bytes': size,
'lines': lines,
'characters': chars,
'has_file_operations': any(keyword in content.lower() for keyword in
['out-file', 'copy-item', 'move-item', 'new-item', 'remove-item']),
'has_long_commands': any(len(line) > 500 for line in content.split('\n')),
'complexity_score': lines + (chars / 100) + (size / 1000)
}
return analysis
def choose_method(self, script_path):
"""Choose optimal execution method"""
analysis = self.analyze_script(script_path)
if not analysis:
return "error"
# Decision logic
if analysis['size_bytes'] > 5000: # Large scripts
return "ssh"
elif analysis['lines'] > 100: # Many lines
return "ssh"
elif analysis['has_file_operations']: # File operations
return "ssh"
elif analysis['has_long_commands']: # Very long command lines
return "ssh"
elif analysis['complexity_score'] > 150: # Complex scripts
return "ssh"
else:
return "winrm" # Simple, fast execution
def execute_via_ssh(self, script_path):
"""Execute script using SSH method"""
script_name = Path(script_path).stem
ssh_script = f"{script_name}.sh"
if not Path(ssh_script).exists():
print(f"❌ SSH wrapper {ssh_script} not found")
return False
try:
result = subprocess.run([f'./{ssh_script}'], capture_output=False, timeout=300)
return result.returncode == 0
except Exception as e:
print(f"❌ SSH execution failed: {e}")
return False
def execute_via_winrm(self, script_path):
"""Execute script using WinRM method"""
try:
# Read and execute script content directly
with open(script_path, 'r', encoding='utf-8') as f:
script_content = f.read()
# Connect via WinRM
session = Session(
f'http://{self.host}:5985/wsman',
auth=(self.username, self.password),
transport='ntlm'
)
# Execute PowerShell
result = session.run_ps(script_content)
# Output results
if result.std_out:
output = result.std_out.decode('utf-8', errors='replace')
for line in output.split('\n'):
if line.strip():
print(line)
if result.std_err:
error = result.std_err.decode('utf-8', errors='replace')
if error.strip():
for line in error.split('\n'):
if line.strip():
print(f"ERROR: {line}")
return result.status_code == 0
except Exception as e:
print(f"❌ WinRM execution failed: {e}")
return False
def execute(self, script_path):
"""Smart execute with automatic method selection"""
script_path = Path(script_path)
print(f"🧠 Analyzing script: {script_path.name}")
analysis = self.analyze_script(script_path)
method = self.choose_method(script_path)
print(f"📊 Script analysis:")
print(f" Size: {analysis['size_bytes']} bytes")
print(f" Lines: {analysis['lines']}")
print(f" Complexity: {analysis['complexity_score']:.1f}")
print(f" File operations: {analysis['has_file_operations']}")
print(f"⚡ Selected method: {method.upper()}")
if method == "ssh":
print("🔗 Executing via SSH (for large/complex scripts)")
return self.execute_via_ssh(script_path)
elif method == "winrm":
print("⚡ Executing via WinRM (for speed)")
return self.execute_via_winrm(script_path)
else:
print("❌ Unable to determine execution method")
return False
def main():
if len(sys.argv) != 2:
print("Usage: python3 smart_executor.py <script.ps1>")
sys.exit(1)
script_path = sys.argv[1]
executor = SmartExecutor()
print("🎯 Smart PowerShell Executor")
print("============================")
success = executor.execute(script_path)
if success:
print(f"\n✅ Script execution completed successfully")
else:
print(f"\n❌ Script execution failed")
sys.exit(1)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,97 @@
#!/usr/bin/env python3
"""
Test simple WinRM script execution
Uses very small commands to avoid length limits
"""
import os
from winrm import Session
def test_simple_script_execution():
host = os.getenv('HOST', '192.168.88.108')
username = os.getenv('USER_NAME', 'Admin')
password = os.getenv('PASS', 'P@ssw0rd!')
print(f"Testing simple WinRM script execution on {host}")
try:
# Connect
session = Session(
f'http://{host}:5985/wsman',
auth=(username, password),
transport='ntlm'
)
# Test 1: Simple inline PowerShell
print("\n[Test 1] Running simple inline PowerShell:")
simple_ps = """
Write-Host "=== Simple WinRM Test ==="
Write-Host "Computer: $env:COMPUTERNAME"
Write-Host "User: $env:USERNAME"
Write-Host "PowerShell: $($PSVersionTable.PSVersion)"
Write-Host "Time: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
Write-Host "=== End Test ==="
"""
result = session.run_ps(simple_ps)
if result.status_code == 0:
print("✅ Simple PowerShell execution successful:")
output = result.std_out.decode('utf-8', errors='replace')
for line in output.split('\n'):
if line.strip():
print(f" {line.strip()}")
else:
print(f"❌ Simple PowerShell failed: {result.std_err.decode()}")
return False
# Test 2: Create small script file
print("\n[Test 2] Creating and executing small script file:")
# Create a very small script
create_script = """
$scriptContent = @'
Write-Host "Small script test"
Get-ComputerInfo -Property CsName, WindowsProductName | Format-List
Write-Host "Small script completed"
'@
$scriptContent | Out-File -FilePath 'C:\\Users\\Admin\\small_test.ps1' -Encoding UTF8
Write-Host "Small script file created"
"""
result = session.run_ps(create_script)
if result.status_code == 0:
print("✅ Script file created successfully")
# Execute the small script
exec_result = session.run_cmd('powershell -NoProfile -ExecutionPolicy Bypass -File C:\\Users\\Admin\\small_test.ps1')
if exec_result.status_code == 0:
print("✅ Script execution successful:")
output = exec_result.std_out.decode('utf-8', errors='replace')
for line in output.split('\n'):
if line.strip():
print(f" {line.strip()}")
return True
else:
print(f"❌ Script execution failed: {exec_result.std_err.decode()}")
return False
else:
print(f"❌ Script creation failed: {result.std_err.decode()}")
return False
except Exception as e:
print(f"❌ Test failed: {e}")
return False
if __name__ == "__main__":
if test_simple_script_execution():
print("\n🎉 Simple WinRM script execution works!")
print("This proves WinRM can execute PowerShell scripts.")
print("The issue is with large script handling, not basic functionality.")
else:
print("\n❌ Basic WinRM functionality failed")

View File

@@ -0,0 +1,96 @@
#!/usr/bin/env python3
"""
Test WinRM with Negotiate authentication (instead of Basic)
"""
import os
from winrm import Session
def test_negotiate_auth():
host = os.getenv('HOST', '192.168.88.108')
username = os.getenv('USER_NAME', 'Admin')
password = os.getenv('PASS', 'P@ssw0rd!')
print(f"Testing WinRM with Negotiate authentication to {host}")
try:
# Try with negotiate/ntlm transport
session = Session(
f'http://{host}:5985/wsman',
auth=(username, password),
transport='ntlm' # Use NTLM instead of plaintext
)
print("✅ Session created with NTLM transport")
# Test simple command
result = session.run_cmd('echo "NTLM test successful"')
if result.status_code == 0:
print(f"✅ Command successful: {result.std_out.decode().strip()}")
return True
else:
print(f"❌ Command failed: {result.std_err.decode()}")
return False
except Exception as e:
print(f"❌ NTLM authentication failed: {e}")
# Try with ssl transport (even though we're using HTTP)
try:
print("Trying with SSL transport (ignore cert validation)...")
session = Session(
f'http://{host}:5985/wsman',
auth=(username, password),
transport='ssl',
server_cert_validation='ignore'
)
print("✅ Session created with SSL transport")
result = session.run_cmd('echo "SSL transport test"')
if result.status_code == 0:
print(f"✅ Command successful: {result.std_out.decode().strip()}")
return True
else:
print(f"❌ Command failed: {result.std_err.decode()}")
return False
except Exception as e2:
print(f"❌ SSL transport also failed: {e2}")
# Try with kerberos if available
try:
print("Trying with Kerberos transport...")
session = Session(
f'http://{host}:5985/wsman',
auth=(username, password),
transport='kerberos'
)
print("✅ Session created with Kerberos transport")
result = session.run_cmd('echo "Kerberos test"')
if result.status_code == 0:
print(f"✅ Command successful: {result.std_out.decode().strip()}")
return True
else:
print(f"❌ Command failed: {result.std_err.decode()}")
return False
except Exception as e3:
print(f"❌ Kerberos transport failed: {e3}")
return False
if __name__ == "__main__":
success = test_negotiate_auth()
if success:
print("\n🎉 Alternative authentication method works!")
else:
print("\n❌ All authentication methods failed")
print("\nThis suggests the issue is with AllowUnencrypted=false")
print("We may need to force this setting or use HTTPS instead")

View File

@@ -0,0 +1,192 @@
#!/usr/bin/env python3
"""
Python WinRM Connection Test
Tests WinRM connectivity using pywinrm library
"""
import os
import sys
from winrm.protocol import Protocol
from winrm import Session
import xml.etree.ElementTree as ET
def test_basic_connection(host, username, password):
"""Test basic WinRM connectivity"""
print(f"[1/4] Testing basic WinRM protocol connection to {host}...")
try:
# Create a basic protocol connection
endpoint = f"http://{host}:5985/wsman"
p = Protocol(
endpoint=endpoint,
transport='plaintext',
username=username,
password=password
)
# Try a simple identify operation
result = p.send_message(
'<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:wsmid="http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd">'
'<s:Header></s:Header>'
'<s:Body>'
'<wsmid:Identify/>'
'</s:Body>'
'</s:Envelope>'
)
print("✅ Basic WinRM protocol connection successful")
# Parse response to get some info
try:
root = ET.fromstring(result)
for elem in root.iter():
if 'ProductVersion' in elem.tag:
print(f" Protocol Version: {elem.text}")
elif 'ProductVendor' in elem.tag:
print(f" Product Vendor: {elem.text}")
except:
pass
return True
except Exception as e:
print(f"❌ Basic connection failed: {e}")
return False
def test_session_connection(host, username, password):
"""Test WinRM session connectivity"""
print(f"\n[2/4] Testing WinRM session connection...")
try:
session = Session(
f'http://{host}:5985/wsman',
auth=(username, password),
transport='plaintext'
)
print("✅ WinRM session created successfully")
return session
except Exception as e:
print(f"❌ Session creation failed: {e}")
return None
def test_command_execution(session):
"""Test basic command execution"""
print(f"\n[3/4] Testing command execution...")
try:
# Test simple command
result = session.run_cmd('echo "Hello from WinRM"')
if result.status_code == 0:
print("✅ Command execution successful")
print(f" Output: {result.std_out.decode().strip()}")
else:
print(f"⚠️ Command execution completed with exit code: {result.status_code}")
print(f" Error: {result.std_err.decode().strip()}")
return True
except Exception as e:
print(f"❌ Command execution failed: {e}")
return False
def test_powershell_execution(session):
"""Test PowerShell script execution"""
print(f"\n[4/4] Testing PowerShell execution...")
try:
# Test PowerShell command
ps_script = """
$info = @{
ComputerName = $env:COMPUTERNAME
UserName = $env:USERNAME
PowerShellVersion = $PSVersionTable.PSVersion.ToString()
WindowsVersion = (Get-ComputerInfo -Property WindowsProductName).WindowsProductName
CurrentTime = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
}
Write-Host "=== Remote System Information ==="
Write-Host "Computer: $($info.ComputerName)"
Write-Host "User: $($info.UserName)"
Write-Host "PowerShell: $($info.PowerShellVersion)"
Write-Host "Windows: $($info.WindowsVersion)"
Write-Host "Time: $($info.CurrentTime)"
Write-Host "=== End Information ==="
"""
result = session.run_ps(ps_script)
if result.status_code == 0:
print("✅ PowerShell execution successful")
print("Remote system info:")
output = result.std_out.decode().strip()
for line in output.split('\n'):
if line.strip():
print(f" {line.strip()}")
else:
print(f"⚠️ PowerShell execution completed with exit code: {result.status_code}")
if result.std_err:
print(f" Error: {result.std_err.decode().strip()}")
return True
except Exception as e:
print(f"❌ PowerShell execution failed: {e}")
return False
def main():
# Get connection details from environment or use defaults
host = os.getenv('HOST', '192.168.88.108')
username = os.getenv('USER_NAME', 'Admin')
password = os.getenv('PASS', 'P@ssw0rd!')
print("=== Python WinRM Connection Test ===")
print(f"Target: {username}@{host}")
print("")
# Test sequence
success = True
# Test 1: Basic connection
if not test_basic_connection(host, username, password):
success = False
print("\n If basic connection fails, ensure:")
print(" - WinRM service is running on target")
print(" - Port 5985 is accessible")
print(" - AllowUnencrypted=true for HTTP connections")
sys.exit(1)
# Test 2: Session creation
session = test_session_connection(host, username, password)
if not session:
success = False
sys.exit(1)
# Test 3: Command execution
if not test_command_execution(session):
success = False
# Test 4: PowerShell execution
if not test_powershell_execution(session):
success = False
if success:
print(f"\n🎉 All tests passed! Python WinRM is working correctly.")
print(f"\nNext steps:")
print(f" 1. Create Python WinRM wrapper for existing scripts")
print(f" 2. Compare performance with SSH method")
print(f" 3. Implement error handling and logging")
else:
print(f"\n⚠️ Some tests failed. Check configuration and try again.")
sys.exit(1)
if __name__ == "__main__":
main()

250
scripts/winrm/winrm_executor.py Executable file
View File

@@ -0,0 +1,250 @@
#!/usr/bin/env python3
"""
WinRM Script Executor
A Python-based alternative to SSH for executing PowerShell scripts on Windows machines.
"""
import os
import sys
import argparse
import json
import time
from datetime import datetime
from pathlib import Path
from winrm import Session
import logging
class WinRMExecutor:
def __init__(self, host, username, password, port=5985, use_https=False):
self.host = host
self.username = username
self.password = password
self.port = port
self.use_https = use_https
self.session = None
# Setup logging
self.setup_logging()
def setup_logging(self):
"""Setup logging configuration"""
log_dir = Path(__file__).parent / "../../logs"
log_dir.mkdir(exist_ok=True)
timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
log_file = log_dir / f"winrm-{self.host}-{timestamp}.log"
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler(log_file),
logging.StreamHandler()
]
)
self.logger = logging.getLogger(__name__)
self.logger.info(f"Starting WinRM session to {self.host}")
def connect(self):
"""Establish WinRM connection"""
try:
protocol = 'https' if self.use_https else 'http'
endpoint = f'{protocol}://{self.host}:{self.port}/wsman'
self.logger.info(f"Connecting to {endpoint}")
self.session = Session(
endpoint,
auth=(self.username, self.password),
transport='ntlm' if not self.use_https else 'ssl',
server_cert_validation='ignore' if self.use_https else 'validate'
)
# Test connection with a simple command
result = self.session.run_cmd('echo Connection test')
if result.status_code == 0:
self.logger.info("✅ WinRM connection established successfully")
return True
else:
self.logger.error(f"❌ Connection test failed: {result.std_err.decode()}")
return False
except Exception as e:
self.logger.error(f"❌ Failed to connect: {e}")
return False
def upload_and_execute_script(self, local_script_path, remote_script_name=None):
"""Upload and execute a PowerShell script"""
if not self.session:
self.logger.error("No active WinRM session")
return False
try:
# Read the local script
with open(local_script_path, 'r', encoding='utf-8') as f:
script_content = f.read()
# Generate remote script name if not provided
if not remote_script_name:
script_name = Path(local_script_path).name
remote_script_name = f"C:\\Users\\{self.username}\\{script_name}"
self.logger.info(f"Uploading script: {local_script_path} -> {remote_script_name}")
# Create the script on remote machine
create_script = f"""
$scriptContent = @'
{script_content}
'@
# Ensure UTF-8 encoding with BOM for Chinese Windows
$utf8BOM = New-Object System.Text.UTF8Encoding($true)
[System.IO.File]::WriteAllText('{remote_script_name}', $scriptContent, $utf8BOM)
Write-Host "Script uploaded to {remote_script_name}"
"""
upload_result = self.session.run_ps(create_script)
if upload_result.status_code != 0:
self.logger.error(f"Failed to upload script: {upload_result.std_err.decode()}")
return False
self.logger.info("✅ Script uploaded successfully")
# Execute the script
self.logger.info(f"Executing PowerShell script: {remote_script_name}")
execute_command = f"PowerShell -NoProfile -ExecutionPolicy Bypass -File '{remote_script_name}'"
result = self.session.run_cmd(execute_command)
# Output results
if result.std_out:
output = result.std_out.decode('utf-8', errors='replace')
self.logger.info("Script Output:")
for line in output.split('\n'):
if line.strip():
print(line)
self.logger.info(line)
if result.std_err:
error = result.std_err.decode('utf-8', errors='replace')
if error.strip():
self.logger.warning("Script Errors:")
for line in error.split('\n'):
if line.strip():
print(f"ERROR: {line}")
self.logger.warning(line)
success = result.status_code == 0
status = "✅ SUCCESS" if success else f"❌ FAILED (exit code: {result.status_code})"
self.logger.info(f"Script execution completed: {status}")
return success
except Exception as e:
self.logger.error(f"❌ Script execution failed: {e}")
return False
def execute_command(self, command, use_powershell=False):
"""Execute a single command"""
if not self.session:
self.logger.error("No active WinRM session")
return False
try:
self.logger.info(f"Executing command: {command}")
if use_powershell:
result = self.session.run_ps(command)
else:
result = self.session.run_cmd(command)
# Output results
if result.std_out:
output = result.std_out.decode('utf-8', errors='replace')
for line in output.split('\n'):
if line.strip():
print(line)
if result.std_err:
error = result.std_err.decode('utf-8', errors='replace')
if error.strip():
for line in error.split('\n'):
if line.strip():
print(f"ERROR: {line}")
return result.status_code == 0
except Exception as e:
self.logger.error(f"Command execution failed: {e}")
return False
def close(self):
"""Close the WinRM session"""
if self.session:
self.logger.info("Closing WinRM session")
# Note: pywinrm doesn't have an explicit close method
self.session = None
def main():
parser = argparse.ArgumentParser(description='Execute PowerShell scripts via WinRM')
parser.add_argument('--host', default=os.getenv('HOST', '192.168.88.108'),
help='Target host (default: from HOST env var or 192.168.88.108)')
parser.add_argument('--username', default=os.getenv('USER_NAME', 'Admin'),
help='Username (default: from USER_NAME env var or Admin)')
parser.add_argument('--password', default=os.getenv('PASS', 'P@ssw0rd!'),
help='Password (default: from PASS env var)')
parser.add_argument('--port', type=int, default=5985,
help='WinRM port (default: 5985)')
parser.add_argument('--https', action='store_true',
help='Use HTTPS instead of HTTP')
parser.add_argument('--script', required=True,
help='PowerShell script file to execute')
parser.add_argument('--test-connection', action='store_true',
help='Test connection only, do not execute script')
args = parser.parse_args()
# Create executor
executor = WinRMExecutor(
host=args.host,
username=args.username,
password=args.password,
port=args.port,
use_https=args.https
)
try:
# Connect
if not executor.connect():
print("❌ Failed to establish WinRM connection")
sys.exit(1)
if args.test_connection:
print("✅ WinRM connection test successful")
return
# Execute script
script_path = Path(args.script)
if not script_path.exists():
print(f"❌ Script file not found: {script_path}")
sys.exit(1)
success = executor.upload_and_execute_script(script_path)
if success:
print(f"\n🎉 Script execution completed successfully")
else:
print(f"\n❌ Script execution failed")
sys.exit(1)
finally:
executor.close()
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,253 @@
#!/usr/bin/env python3
"""
Improved WinRM Script Executor
Handles large scripts by uploading them in chunks
"""
import os
import sys
import argparse
import json
import time
import base64
from datetime import datetime
from pathlib import Path
from winrm import Session
import logging
class WinRMExecutorV2:
def __init__(self, host, username, password, port=5985, use_https=False):
self.host = host
self.username = username
self.password = password
self.port = port
self.use_https = use_https
self.session = None
# Setup logging
self.setup_logging()
def setup_logging(self):
"""Setup logging configuration"""
log_dir = Path(__file__).parent / "../../logs"
log_dir.mkdir(exist_ok=True)
timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
log_file = log_dir / f"winrm-v2-{self.host}-{timestamp}.log"
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler(log_file),
logging.StreamHandler()
]
)
self.logger = logging.getLogger(__name__)
self.logger.info(f"Starting WinRM session to {self.host}")
def connect(self):
"""Establish WinRM connection"""
try:
protocol = 'https' if self.use_https else 'http'
endpoint = f'{protocol}://{self.host}:{self.port}/wsman'
self.logger.info(f"Connecting to {endpoint}")
self.session = Session(
endpoint,
auth=(self.username, self.password),
transport='ntlm' if not self.use_https else 'ssl',
server_cert_validation='ignore' if self.use_https else 'validate'
)
# Test connection with a simple command
result = self.session.run_cmd('echo Connection test')
if result.status_code == 0:
self.logger.info("✅ WinRM connection established successfully")
return True
else:
self.logger.error(f"❌ Connection test failed: {result.std_err.decode()}")
return False
except Exception as e:
self.logger.error(f"❌ Failed to connect: {e}")
return False
def upload_script_chunked(self, local_script_path, remote_script_name):
"""Upload script in chunks to avoid command line length limits"""
try:
# Read the local script
with open(local_script_path, 'r', encoding='utf-8') as f:
script_content = f.read()
self.logger.info(f"Uploading script in chunks: {local_script_path} -> {remote_script_name}")
# Encode content as base64 to avoid special character issues
script_bytes = script_content.encode('utf-8')
script_b64 = base64.b64encode(script_bytes).decode('ascii')
# Split into chunks of 8000 chars (safe for command line)
chunk_size = 8000
chunks = [script_b64[i:i+chunk_size] for i in range(0, len(script_b64), chunk_size)]
self.logger.info(f"Uploading {len(chunks)} chunks...")
# Create the file and append chunks
for i, chunk in enumerate(chunks):
if i == 0:
# First chunk - create file
ps_command = f"""
$chunk = '{chunk}'
$chunk | Out-File -FilePath '{remote_script_name}.b64' -Encoding ASCII
"""
else:
# Subsequent chunks - append
ps_command = f"""
$chunk = '{chunk}'
$chunk | Out-File -FilePath '{remote_script_name}.b64' -Encoding ASCII -Append
"""
result = self.session.run_ps(ps_command)
if result.status_code != 0:
self.logger.error(f"Failed to upload chunk {i+1}: {result.std_err.decode()}")
return False
if (i + 1) % 10 == 0:
self.logger.info(f"Uploaded {i+1}/{len(chunks)} chunks...")
# Decode the base64 file to create the final script
decode_command = f"""
$b64Content = Get-Content '{remote_script_name}.b64' -Raw
$bytes = [System.Convert]::FromBase64String($b64Content)
# Write with UTF-8 BOM for Chinese Windows compatibility
$utf8BOM = New-Object System.Text.UTF8Encoding($true)
[System.IO.File]::WriteAllBytes('{remote_script_name}', $bytes)
# Clean up temporary file
Remove-Item '{remote_script_name}.b64' -ErrorAction SilentlyContinue
Write-Host "Script uploaded successfully to {remote_script_name}"
"""
result = self.session.run_ps(decode_command)
if result.status_code == 0:
self.logger.info("✅ Script uploaded and decoded successfully")
return True
else:
self.logger.error(f"Failed to decode script: {result.std_err.decode()}")
return False
except Exception as e:
self.logger.error(f"❌ Script upload failed: {e}")
return False
def execute_script(self, remote_script_name):
"""Execute the uploaded PowerShell script"""
try:
self.logger.info(f"Executing PowerShell script: {remote_script_name}")
# Execute the script
execute_command = f"PowerShell -NoProfile -ExecutionPolicy Bypass -File '{remote_script_name}'"
result = self.session.run_cmd(execute_command)
# Output results in real-time
if result.std_out:
output = result.std_out.decode('utf-8', errors='replace')
self.logger.info("Script Output:")
for line in output.split('\n'):
if line.strip():
print(line)
if result.std_err:
error = result.std_err.decode('utf-8', errors='replace')
if error.strip():
self.logger.warning("Script Errors:")
for line in error.split('\n'):
if line.strip():
print(f"ERROR: {line}")
success = result.status_code == 0
status = "✅ SUCCESS" if success else f"❌ FAILED (exit code: {result.status_code})"
self.logger.info(f"Script execution completed: {status}")
return success
except Exception as e:
self.logger.error(f"❌ Script execution failed: {e}")
return False
def upload_and_execute_script(self, local_script_path, remote_script_name=None):
"""Upload and execute a PowerShell script using chunked upload"""
if not self.session:
self.logger.error("No active WinRM session")
return False
# Generate remote script name if not provided
if not remote_script_name:
script_name = Path(local_script_path).name
remote_script_name = f"C:\\Users\\{self.username}\\{script_name}"
# Upload script
if not self.upload_script_chunked(local_script_path, remote_script_name):
return False
# Execute script
return self.execute_script(remote_script_name)
def close(self):
"""Close the WinRM session"""
if self.session:
self.logger.info("Closing WinRM session")
self.session = None
def main():
parser = argparse.ArgumentParser(description='Execute PowerShell scripts via WinRM (v2)')
parser.add_argument('--host', default=os.getenv('HOST', '192.168.88.108'),
help='Target host')
parser.add_argument('--username', default=os.getenv('USER_NAME', 'Admin'),
help='Username')
parser.add_argument('--password', default=os.getenv('PASS', 'P@ssw0rd!'),
help='Password')
parser.add_argument('--script', required=True,
help='PowerShell script file to execute')
args = parser.parse_args()
# Create executor
executor = WinRMExecutorV2(
host=args.host,
username=args.username,
password=args.password
)
try:
# Connect
if not executor.connect():
sys.exit(1)
# Execute script
script_path = Path(args.script)
if not script_path.exists():
print(f"❌ Script file not found: {script_path}")
sys.exit(1)
success = executor.upload_and_execute_script(script_path)
if success:
print(f"\n🎉 Script execution completed successfully")
else:
sys.exit(1)
finally:
executor.close()
if __name__ == "__main__":
main()