<# .SYNOPSIS (For Remote Execution) Checks for and enables the OpenSSH Server feature on Windows. Starts the SSHD service and sets it to start automatically. Creates a local user 'txry' with password 'txry' and adds them to the Administrators group. REQUIRES the script to be executed with Administrator privileges. It will NOT attempt self-elevation. .DESCRIPTION This script automates the setup of OpenSSH Server on a Windows machine, intended for remote execution where the initial process already has administrative rights (e.g., via WinRM, PsExec, Task Scheduler as Admin). 1. Checks for Administrator privileges and exits if not present. 2. Checks if the OpenSSH Server feature is installed. If not, installs it. 3. Checks if the 'sshd' service is running. If not, starts it and verifies. 4. Sets the 'sshd' service startup type to Automatic. 5. Checks if the local user 'txry' exists. If not, creates it. 6. Sets the password for the user 'txry' to 'txry'. 7. Adds the user 'txry' to the local Administrators group and verifies. .NOTES Author: Your Name/AI Assistant Date: 2023-10-27 (Revised for Remote Execution) Requires: Windows 10 Version 1809 / Windows Server 2019 or later. PowerShell 5.1 or later. Run this script via a remote mechanism that already provides Administrator privileges. WARNING: Using a simple password like 'txry' is highly insecure and only suitable for testing. Adding the user directly to the Administrators group grants high privileges. Evaluate security risks. #> # --- Script Parameters --- $sshServiceName = "sshd" $sshServerFeatureName = "OpenSSH.Server*" # Use wildcard to match version $sshUserName = "txry" # WARNING: Insecure password! Use for testing only. Consider security implications. $sshPassword = "txry" # --- Main Script Logic --- # 1. Check for Administrator Privileges (No self-elevation attempt) Write-Host "检查管理员权限..." if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { Write-Error "错误:此脚本必须以管理员权限运行。远程执行机制 (如 WinRM, PsExec, Task Scheduler) 必须使用管理员账户或配置为以最高权限运行。" Exit 1 # Exit immediately if not admin } else { Write-Host "脚本正在以管理员权限运行。" } Write-Host "-----------------------------------------" Write-Host "开始配置 OpenSSH 服务器和用户 '$sshUserName' (用于远程执行)..." Write-Host "-----------------------------------------" # Convert password to SecureString $securePassword = ConvertTo-SecureString -String $sshPassword -AsPlainText -Force try { # 2. Check and Install OpenSSH Server Feature Write-Host "检查 OpenSSH 服务器功能..." $sshFeature = Get-WindowsCapability -Online -Name $sshServerFeatureName -ErrorAction SilentlyContinue if ($null -eq $sshFeature -or $sshFeature.State -ne 'Installed') { Write-Host "OpenSSH 服务器功能未安装。正在尝试安装..." # Use -Wait to ensure the command finishes before proceeding (though Add-WindowsCapability might be async internally) Add-WindowsCapability -Online -Name $sshServerFeatureName # Removed -Wait as it's not a valid param # Wait a bit for potential background installation tasks Write-Host "等待功能安装完成..." Start-Sleep -Seconds 15 $sshFeature = Get-WindowsCapability -Online -Name $sshServerFeatureName if ($null -eq $sshFeature -or $sshFeature.State -ne 'Installed') { Write-Error "错误:安装 OpenSSH 服务器功能失败。请检查日志或手动安装。" Exit 1 } Write-Host "OpenSSH 服务器功能已成功安装。" } else { Write-Host "OpenSSH 服务器功能已安装。" } # 3. Check and Start SSHD Service Write-Host "检查 SSHD 服务状态..." $sshService = Get-Service -Name $sshServiceName -ErrorAction SilentlyContinue if ($null -eq $sshService) { Write-Error "错误:找不到 SSHD 服务 ($sshServiceName)。可能是安装未完全完成或出现问题。" Exit 1 } if ($sshService.Status -ne 'Running') { Write-Host "SSHD 服务未运行。正在尝试启动..." Start-Service -Name $sshServiceName # Wait a moment for the service to start and verify Start-Sleep -Seconds 5 $sshService.Refresh() # Refresh service object state if ($sshService.Status -ne 'Running') { Write-Error "错误:启动 SSHD 服务失败。请检查事件查看器中的系统日志获取详细信息。" # Attempt to query the service again after a longer pause, maybe it's slow Start-Sleep -Seconds 10 $sshService.Refresh() if ($sshService.Status -ne 'Running') { Write-Error "错误:再次检查后,SSHD 服务仍未运行。" Exit 1 } else { Write-Host "SSHD 服务在第二次检查时已启动。" } } else { Write-Host "SSHD 服务已成功启动。" } } else { Write-Host "SSHD 服务已在运行。" } # 4. Set SSHD Service Startup Type to Automatic if ($sshService.StartType -ne 'Automatic') { Write-Host "将 SSHD 服务的启动类型设置为 '自动'..." Set-Service -Name $sshServiceName -StartupType Automatic # Verify change $sshService.Refresh() if ($sshService.StartType -eq 'Automatic') { Write-Host "SSHD 服务启动类型已成功设置为 '自动'。" } else { Write-Warning "警告:尝试设置 SSHD 服务启动类型为 '自动',但验证失败。当前类型: $($sshService.StartType)" } } else { Write-Host "SSHD 服务启动类型已经是 '自动'。" } # 5. Check and Create Local User Write-Host "检查本地用户 '$sshUserName'..." $userExists = $false try { Get-LocalUser -Name $sshUserName -ErrorAction Stop | Out-Null $userExists = $true Write-Host "用户 '$sshUserName' 已存在。" } catch [Microsoft.PowerShell.Commands.UserNotFoundException] { Write-Host "用户 '$sshUserName' 不存在。正在创建..." try { New-LocalUser -Name $sshUserName -Password $securePassword -FullName "$sshUserName SSH User" -Description "用于 SSH 访问的用户" -PasswordNeverExpires -ErrorAction Stop # You might want to remove -PasswordNeverExpires Write-Host "用户 '$sshUserName' 已成功创建。" # Set password again immediately after creation, sometimes helps ensure it's set Set-LocalUser -Name $sshUserName -Password $securePassword Write-Host "已设置用户 '$sshUserName' 的密码。" $userExists = $true } catch { Write-Error "错误:创建用户 '$sshUserName' 失败: $($_.Exception.Message)" Exit 1 } } catch { Write-Error "错误:检查用户 '$sshUserName' 时发生意外错误: $($_.Exception.Message)" Exit 1 } # If user exists (either pre-existing or just created), ensure password is set if ($userExists) { Write-Host "确保用户 '$sshUserName' 密码已设置为所需值..." try { Set-LocalUser -Name $sshUserName -Password $securePassword -ErrorAction Stop Write-Host "已确认/更新用户 '$sshUserName' 的密码。" } catch { Write-Error "错误:为用户 '$sshUserName' 设置密码失败: $($_.Exception.Message)" # Don't necessarily exit here, maybe adding to group is still desired if password failed } } else { Write-Error "错误:未能创建或找到用户 '$sshUserName',无法继续。" Exit 1 } # 6. Add User to Administrators Group Write-Host "将用户 '$sshUserName' 添加到 'Administrators' 组..." $adminGroup = "Administrators" try { $members = Get-LocalGroupMember -Group $adminGroup -ErrorAction Stop if ($members.Name -contains $sshUserName) { Write-Host "用户 '$sshUserName' 已经是 '$adminGroup' 组的成员。" } else { Add-LocalGroupMember -Group $adminGroup -Member $sshUserName -ErrorAction Stop Write-Host "正在验证用户 '$sshUserName' 是否已添加到 '$adminGroup' 组..." Start-Sleep -Seconds 2 # Give a moment for the change to propagate $membersAfterAdd = Get-LocalGroupMember -Group $adminGroup -ErrorAction SilentlyContinue # Use SilentlyContinue for verification if ($membersAfterAdd.Name -contains $sshUserName) { Write-Host "用户 '$sshUserName' 已成功添加到 '$adminGroup' 组。" } else { Write-Warning "警告:尝试将用户 '$sshUserName' 添加到 '$adminGroup' 组,但验证失败。请手动检查组成员。" } } } catch { Write-Error "错误:操作本地组 '$adminGroup' 时发生错误: $($_.Exception.Message)" Write-Error "未能将用户 '$sshUserName' 添加到管理员组。" # Depending on requirements, you might Exit 1 here or allow script to finish } Write-Host "-----------------------------------------" Write-Host "配置脚本执行完毕!" Write-Host "请检查上面的输出确认所有步骤是否成功。" Write-Host "如果一切顺利,应该可以使用以下凭据通过 SSH 连接到此计算机:" Write-Host "用户名: $sshUserName" Write-Host "密码: $sshPassword" Write-Host "重要安全警告:密码 '$sshPassword' 非常不安全,仅供测试!强烈建议更改为强密码或使用密钥认证!" Write-Host "重要安全警告:用户 '$sshUserName' 已被添加到 Administrators 组,拥有完全权限!请评估安全风险!" Write-Host "确保防火墙允许 SSH (TCP 端口 22) 的入站连接 (通常由 OpenSSH 功能安装自动处理)。" Write-Host "-----------------------------------------" } catch { Write-Error "脚本执行过程中发生未捕获的顶层错误:" # Try to get more details from the error record $ErrorMessage = $_.Exception.Message if ($_.InvocationInfo) { $ErrorMessage += " (脚本: $($_.InvocationInfo.ScriptName), 行: $($_.InvocationInfo.ScriptLineNumber))" } Write-Error $ErrorMessage # Uncomment the next line for full stack trace if needed for debugging # Write-Error $_.Exception.ToString() Write-Error "脚本已中止。" Exit 1 } # Exit with success code 0 if we reached the end without explicit exit 1 Exit 0