176 lines
5.8 KiB
PowerShell
176 lines
5.8 KiB
PowerShell
# ==========================================
|
|
# 🖥️ SYSTEM UTILS
|
|
# ==========================================
|
|
|
|
|
|
# --- СИСТЕМНАЯ ИНФОРМАЦИЯ ---
|
|
|
|
function Get-SystemInfo {
|
|
return @{
|
|
os = "windows"
|
|
version = [System.Environment]::OSVersion.Version.Major.ToString()
|
|
}
|
|
}
|
|
|
|
function Ensure-VCRedist {
|
|
Write-Info "Проверка Visual C++ Redistributable..."
|
|
|
|
# Check registry for VC++ 2015-2022 (x64)
|
|
# Key: HKLM:\SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x64
|
|
$regPath = "HKLM:\SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x64"
|
|
if (Test-Path $regPath) {
|
|
$installed = (Get-ItemProperty -Path $regPath).Installed
|
|
if ($installed -eq 1) {
|
|
Write-Success "Visual C++ Redistributable уже установлен."
|
|
return
|
|
}
|
|
}
|
|
|
|
Write-Warning "Visual C++ Redistributable не найден. Устанавливаю..."
|
|
|
|
$vcUrl = "https://aka.ms/vs/17/release/vc_redist.x64.exe"
|
|
$vcFile = "$env:TEMP\vc_redist.x64.exe"
|
|
|
|
if (Download-File -Url $vcUrl -Destination $vcFile) {
|
|
Write-Step "Установка библиотек Visual C++..."
|
|
$process = Start-Process -FilePath $vcFile -ArgumentList "/install", "/quiet", "/norestart" -PassThru -Wait
|
|
|
|
if ($process.ExitCode -eq 0 -or $process.ExitCode -eq 3010) {
|
|
# 3010 = reboot required (usually works without immediate reboot)
|
|
Write-Success "Библиотеки установлены!"
|
|
}
|
|
else {
|
|
Write-Error "Ошибка установки VC++ (Код: $($process.ExitCode))"
|
|
Write-Host " Попробуйте установить вручную: https://aka.ms/vs/17/release/vc_redist.x64.exe"
|
|
}
|
|
|
|
Remove-Item $vcFile -Force -ErrorAction SilentlyContinue
|
|
}
|
|
}
|
|
|
|
# --- DOCKER ---
|
|
|
|
function Test-Docker {
|
|
$status = @{
|
|
Installed = $false
|
|
Running = $false
|
|
Compose = $false
|
|
}
|
|
|
|
try {
|
|
$ver = docker --version 2>&1
|
|
if ($LASTEXITCODE -eq 0) { $status.Installed = $true }
|
|
}
|
|
catch {}
|
|
|
|
if ($status.Installed) {
|
|
try {
|
|
$info = docker info 2>&1
|
|
if ($LASTEXITCODE -eq 0) { $status.Running = $true }
|
|
}
|
|
catch {}
|
|
}
|
|
|
|
if ($status.Running) {
|
|
try {
|
|
$comp = docker compose version 2>&1
|
|
if ($LASTEXITCODE -eq 0) { $status.Compose = $true }
|
|
}
|
|
catch {
|
|
# Check legacy
|
|
try {
|
|
$comp = docker-compose --version 2>&1
|
|
if ($LASTEXITCODE -eq 0) { $status.Compose = $true }
|
|
}
|
|
catch {}
|
|
}
|
|
}
|
|
|
|
return $status
|
|
}
|
|
|
|
# --- СЛУЖБЫ И ЗАДАЧИ ---
|
|
|
|
function Manage-ScheduledTask {
|
|
param(
|
|
[string]$Name,
|
|
[string]$ExePath,
|
|
[string]$Arguments,
|
|
[string]$WorkDir,
|
|
[string]$Action = "Install" # Install, Uninstall, Start, Stop
|
|
)
|
|
|
|
switch ($Action) {
|
|
"Install" {
|
|
# Удаляем старую
|
|
Unregister-ScheduledTask -TaskName $Name -Confirm:$false -ErrorAction SilentlyContinue
|
|
|
|
$act = New-ScheduledTaskAction -Execute "$ExePath" -Argument "$Arguments" -WorkingDirectory $WorkDir
|
|
$trig = New-ScheduledTaskTrigger -AtStartup
|
|
$princ = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest
|
|
$sett = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable -RestartCount 3 -RestartInterval (New-TimeSpan -Minutes 1)
|
|
|
|
Register-ScheduledTask -TaskName $Name -Action $act -Trigger $trig -Principal $princ -Settings $sett -Force | Out-Null
|
|
return $true
|
|
}
|
|
"Uninstall" {
|
|
Unregister-ScheduledTask -TaskName $Name -Confirm:$false -ErrorAction SilentlyContinue
|
|
}
|
|
"Start" {
|
|
Start-ScheduledTask -TaskName $Name -ErrorAction SilentlyContinue
|
|
}
|
|
"Stop" {
|
|
Stop-ScheduledTask -TaskName $Name -ErrorAction SilentlyContinue
|
|
# Пытаемся убить процесс по имени exe
|
|
if ($ExePath) {
|
|
$procName = [System.IO.Path]::GetFileNameWithoutExtension($ExePath)
|
|
if ($procName) {
|
|
Stop-Process -Name $procName -Force -ErrorAction SilentlyContinue
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function Get-TaskStatus {
|
|
param([string]$Name)
|
|
$task = Get-ScheduledTask -TaskName $Name -ErrorAction SilentlyContinue
|
|
if ($task) {
|
|
# Если задача в статусе Running — возвращаем Running
|
|
if ($task.State -eq "Running") {
|
|
return "Running"
|
|
}
|
|
|
|
# Если задача Ready — проверяем, работает ли процесс sing-box
|
|
# (scheduled task может быть Ready даже когда процесс работает)
|
|
$process = Get-Process -Name "sing-box" -ErrorAction SilentlyContinue
|
|
if ($process) {
|
|
return "Running"
|
|
}
|
|
|
|
return $task.State
|
|
}
|
|
return $null
|
|
}
|
|
|
|
|
|
|
|
function Ensure-FirewallPort {
|
|
param(
|
|
[int]$Port,
|
|
[string]$Name,
|
|
[string]$Protocol = "TCP"
|
|
)
|
|
|
|
$rule = Get-NetFirewallRule -DisplayName $Name -ErrorAction SilentlyContinue
|
|
if (-not $rule) {
|
|
New-NetFirewallRule -DisplayName $Name -Direction Inbound -LocalPort $Port -Protocol $Protocol -Action Allow -Profile Any | Out-Null
|
|
return $true
|
|
}
|
|
return $false
|
|
}
|
|
|
|
function Get-LocalIPs {
|
|
return (Get-NetIPAddress -AddressFamily IPv4 -InterfaceAlias * | Where-Object { $_.IPAddress -notmatch "^127\." -and $_.IPAddress -notmatch "^169\.254\." }).IPAddress
|
|
}
|