Skip to content

Commit

Permalink
Updated Bootstrap-RemoteHostViaSSHWithPSRemoting.ps1
Browse files Browse the repository at this point in the history
  • Loading branch information
pldmgg committed Jan 12, 2024
1 parent f5909c3 commit a569ee3
Showing 1 changed file with 284 additions and 0 deletions.
284 changes: 284 additions & 0 deletions MyScripts/Bootstrap-RemoteHostViaSSHWithPSRemoting.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,284 @@
<#
# Get a Windows 11 ISO ready to install
# Create new bootable Windows 11 ISO via D:\ drive with all of the files generated by Rufus
New-VHD -Path "E:\HDDs\Win11InstallerViaRufus\Win11_22H2_v2.vhdx" -Fixed -SizeBytes 10GB
# Use the Disk Management GUI to initialize the new disk and create a new simple NTFS volume and mount it as D:\ (or whatever letter)
# Use the Rufus GUI to create a bootable Windows 11 D:\ drive with all desired customizations
# Copy the boot files to a folder on a different letter drive like C:\
$ISOFilesDir = "C:\Win1122H2v2_ISO_via_Rufus"
$ISOFileOutputPath = "C:\Users\adminuser\Downloads\Custom_Win11_22H2_v2_adminuser_via_Rufus.iso"
if (!(Test-Path $ISOFilesDir)) {$null = New-Item -Path $ISOFilesDir -ItemType Directory -Force}
Copy-Item -Path D:\* -Destination $ISOFilesDir -Recurse -Force
# Make sure you have Windows ADK installed and run the following commands in an elevated PowerShell prompt
cd "C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\amd64\Oscdimg"
Invoke-Expression ".\oscdimg.exe -m -o -u2 -udfver102 -bootdata:2#p0,e,b$ISOFilesDir\boot\etfsboot.com#pEF,e,b$ISOFilesDir\efi\microsoft\boot\efisys.bin -lWinBoot $ISOFilesDir $ISOFileOutputPath"
#>

# Bootstrap new Windows Workstation
# You Just need to have SSHD installed and running on the remote host and default shell must be powershell.exe
# To get SSHD installed, on the new Windows 11 machine, lauch Powershell as admin and run the following command:
# Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/pldmgg/misc-powershell/master/MyScripts/Install-SSHD.ps1'))

# Next, from your local workstation, run:
$ScriptsDir = "C:\Scripts"
@("$ScriptsDir\temp", "$ScriptsDir\logs", "$ScriptsDir\bin", "$ScriptsDir\powershell") | foreach {
if (!(Test-Path $_)) {
$null = New-Item -Path $_ -ItemType Directory -Force
}
}

$ModuleBaseUri = "https://raw.githubusercontent.com/pldmgg/misc-powershell/master/MyModules"
$ScriptsBaseUri = "https://raw.githubusercontent.com/pldmgg/misc-powershell/master/MyScripts"
@(
"$ModuleBaseUri/BootstrapRemoteHost.psm1"
"$ModuleBaseUri/MiniServeModule.psm1"
"$ModuleBaseUri/TTYDModule.psm1"
"$ScriptsBaseUri/Install-ZeroTier.ps1"
) | foreach {
if (!(Test-Path "$ScriptsDir\powershell\$(Split-Path $_ -Leaf)")) {
$null = Invoke-WebRequest -Uri $_ -OutFile "$ScriptsDir\powershell\$(Split-Path $_ -Leaf)"
}
}

$ScriptsDir = "C:\Scripts"
Import-Module "$ScriptsDir\powershell\BootstrapRemoteHost.psm1"
$NewComputerName = "win11services1"
$RemoteIPAddress = "192.168.2.68"
$RemoteUserName = "adminuser"
$SSHUserAndHost = $RemoteUserName + "@" + $RemoteIPAddress
$SSHPrivateKeyPath = "C:\Users\adminuser\.ssh\id_rsa_for_remote_commands"
$SSHPublicKeyPath = $SSHPrivateKeyPath + ".pub"
$ZTScriptPath = "$ScriptsDir\powershell\Install-ZeroTier.ps1"
$ZTNetworkID = 'id'
$ZTToken = 'token'
Invoke-ScaffoldingOnRemoteHost -RemoteUserName $RemoteUserName -RemoteIPAddress $RemoteIPAddress

$SendKeyParams = @{
RemoteUserName = $RemoteUserName
RemoteIPAddress = $RemoteIPAddress
SSHPrivateKeyPath = $SSHPrivateKeyPath
SSHPublicKeyPath = $SSHPublicKeyPath
}
Send-SSHKeyToRemoteHost @SendKeyParams

# Set Execution Policy to RemoteSigned so that scripts created locally can run
ssh -i $SSHPrivateKeyPath $SSHUserAndHost "powershell.exe -ExecutionPolicy Bypass -Command `"Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser`""

# Set profile.ps1
# The below line at the top of profile.ps1 ensures that $env:Path does not have any repeated entries
#The final line within profile.ps1 looks like - $env:Path = ($env:Path -split ';' | Sort-Object | Get-Unique) -join ';'
ssh -i $SSHPrivateKeyPath $SSHUserAndHost "cmd /c echo `"```$env:Path = (```$env:Path -split ';' | Sort-Object | Get-Unique) -join ';'`" > C:\Windows\System32\WindowsPowerShell\v1.0\profile.ps1; (Get-Content C:\Windows\System32\WindowsPowerShell\v1.0\profile.ps1).Trim('`"') | Out-File C:\Windows\System32\WindowsPowerShell\v1.0\profile.ps1"

# Install Pwsh
$PwshScriptPath = "$ScriptsDir\powershell\Install-Pwsh.ps1"
$SCPPwshRemoteLocationString = $RemoteUserName + '@' + $RemoteIPAddress + ':' + $PwshScriptPath
scp.exe -i $SSHPrivateKeyPath $PwshScriptPath $SCPPwshRemoteLocationString
ssh -i $SSHPrivateKeyPath $SSHUserAndHost "powershell.exe -ExecutionPolicy Bypass -Command `"& $PwshScriptPath`""
# Optionally set the default sshd shell to pwsh in the registry.
ssh -i $SSHPrivateKeyPath $SSHUserAndHost "powershell.exe -ExecutionPolicy Bypass -Command `"Set-ItemProperty -Path HKLM:\SOFTWARE\OpenSSH -Name DefaultShell -Value ((Get-Command pwsh).Source); Restart-Service sshd`""
# NOTE: If you're going to use Invoke-Command/New-PSSession over ssh, then the below sshd_config subsystem changes are required
$SSHDConfigPath = "C:\ProgramData\ssh\sshd_config"
$PwshSubsystemString = "Subsystem powershell c:/progra~1/powershell/7/pwsh.exe -sshs -nologo"
$OverrideSubsystemsString = "# override default of no subsystems"
$RemoteSSHDConfig = ssh -i $SSHPrivateKeyPath $SSHUserAndHost "powershell.exe -ExecutionPolicy Bypass -Command `"Stop-Service sshd; if ((Get-Content '$SSHDConfigPath') -notcontains '$PwshSubsystemString') {(Get-Content '$SSHDConfigPath') -replace [Regex]::Escape('$OverrideSubsystemsString'), ('$OverrideSubsystemsString' + [Environment]::NewLine + '$PwshSubsystemString') | Set-Content '$SSHDConfigPath'}; Start-Service sshd; Get-Content '$SSHDConfigPath'`""

# Now you can use pwsh remoting commands. Create a PSSession and then we can use Invoke-Command
try {
$PSSession1 = New-PSSession -HostName $RemoteIPAddress -UserName $RemoteUserName -IdentityFilePath $SSHPrivateKeyPath -ErrorAction Stop
} catch {
Write-Output "Failed to create PSSession1 to $RemoteIPAddress"
Write-Error $_
return
}

Invoke-Command $PSSession1 -ScriptBlock {
$ScriptsDir = $using:ScriptsDir
$NewComputerName = $using:NewComputerName

# Enable ICMP Ping
Set-NetFirewallRule -DisplayName 'File and Printer Sharing (Echo Request - ICMPv4-In)' -Enabled True

# Enable RDP
Set-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server' -Name 'fDenyTSConnections' -Value 0
# Disable RDP via
# ssh -i $SSHPrivateKeyPath $SSHUserAndHost "powershell.exe -ExecutionPolicy Bypass -Command `"Set-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server' -Name 'fDenyTSConnections' -Value 1`""

# Set Timezone
Get-TimeZone -Id 'Eastern Standard Time' | Set-TimeZone

# Rename Computer
Rename-Computer -NewName $NewComputerName -Restart
}

# Remote Machine is rebooting, so destroy the PSSession
$PSSession1 | Remove-PSSession

Write-Output "Remote Host is rebooting after renaming it...please wait 2 minutes..."
Start-Sleep -Seconds 90

# Create a new PSSession to ensure that the machine has rebooted
try {
$PSSession2 = New-PSSession -HostName $RemoteIPAddress -UserName $RemoteUserName -IdentityFilePath $SSHPrivateKeyPath -ErrorAction Stop
} catch {
Write-Output "Failed to create PSSession2 to $RemoteIPAddress"
Write-Error $_
return
}

# Install ZeroTier
$SCPRemoteLocationString = $RemoteUserName + '@' + $RemoteIPAddress + ':' + $ZTScriptPath
scp.exe -i $SSHPrivateKeyPath $ZTScriptPath $SCPRemoteLocationString

Invoke-Command $PSSession2 -ScriptBlock {
$ScriptsDir = $using:ScriptsDir
$ZTScriptPath = $using:ZTScriptPath
$ZTNetworkID = $using:ZTNetworkID
$ZTToken = $using:ZTToken

# Install ZeroTier
& $ZTScriptPath -NetworkID $ZTNetworkID -Token $ZTToken

# Disable Bitlocker and Decrypt on ALL Volumes
Disable-BitLocker -MountPoint (Get-BitLockerVolume) -Confirm:$false

# Install the latest version of winget
$Owner = "microsoft"
$Repo = "winget-cli"
$ReleaseInfo = Invoke-RestMethod -Uri "https://api.github.com/repos/$Owner/$Repo/releases/latest"
$Asset = $ReleaseInfo.assets | Where-Object {$_.Name -match "msixbundle"}
$AssetUrl = $Asset.browser_download_url
$AssetName = $Asset.Name
$AssetVersion = [version]$($AssetUrl.Split("/")[-2] -replace 'v','')
$DownloadPath = "$env:USERPROFILE\Downloads\$AssetName"
Invoke-WebRequest -Uri $AssetUrl -OutFile $DownloadPath -ErrorAction Stop
$MsixBundleRemotePath = "$ScriptsDir\bin\$AssetName"

dism.exe /Online /Add-ProvisionedAppxPackage /PackagePath:$MsixBundleRemotePath /SkipLicense

winget install Google.Chrome
winget install NoMachine.NoMachine
#winget install VMware.WorkstationPlayer
#Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V-All -NoRestart; Restart-Computer -Force
}

# Remote Machine might be rebooting, so destroy the PSSession
$PSSession2 | Remove-PSSession

Write-Output "Remote Host is rebooting after HyperV install...please wait 2 minutes..."
Start-Sleep Seconds 90

# Create a new PSSession to ensure that the machine has rebooted
try {
$PSSession3 = New-PSSession -HostName $RemoteIPAddress -UserName $RemoteUserName -IdentityFilePath $SSHPrivateKeyPath -ErrorAction Stop
} catch {
Write-Output "Failed to create PSSession3 to $RemoteIPAddress"
Write-Error $_
return
}

Invoke-Command $PSSession3 -ScriptBlock {
# Install Chocolatey
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))

# Update Machine and User PATH
[Environment]::SetEnvironmentVariable('Path', (([Environment]::GetEnvironmentVariable('Path', 'Machine')).Trim(';') + ';C:\ProgramData\chocolatey\bin;C:\ProgramData\chocolatey\lib'), 'Machine')
[Environment]::SetEnvironmentVariable('Path', (([Environment]::GetEnvironmentVariable('Path', 'User')).Trim(';') + ';C:\ProgramData\chocolatey\bin;C:\ProgramData\chocolatey\lib'), 'User')

choco install lockhunter -y
choco install vscode -y
choco install nano -y
choco install veeam-agent -y

# Veeam Agent Requires a reboot
Restart-Computer -Force
}

Write-Output "Remote Host is rebooting after installing Veeam Agent...please wait 2 minutes..."
Start-Sleep -Seconds 90

# OPTIONAL 1: Install WSL
# IMPORTANT NOTE: For some reason the installer fails unless it thinks you're logged into a GUI session
mstsc /v:$RemoteIPAddress
# And within the RDP Session, run the following commands in the below comment block
<#
wsl --install
Restart-Computer -Force
#winget install -e --id Canonical.Ubuntu.2204
mstsc /v:$RemoteIPAddress
# Just wait for wsl to pop open a window to finish the install
wsl
sudo apt update && sudo apt upgrade -y
sudo apt install openssh-server -y
sudo sed -i -E 's,^#?Port.*$,Port 2222,' /etc/ssh/sshd_config
sudo service ssh restart
sudo sh -c "echo '${USER} ALL=(root) NOPASSWD: /usr/sbin/service ssh start' >/etc/sudoers.d/service-ssh-start"
exit
# Now you should be back in powershell on the remote host within an RDP session
# Allow ssh traffic on port 2222
New-NetFirewallRule -Name wsl_sshd -DisplayName 'OpenSSH Server (sshd) for WSL' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 2222
# Now we want to create a scheduled task that will start WSL AND ssh within WSL on boot
$ScriptOutputPath = "C:\Scripts\bin\wsl_sshd.ps1"
$ScriptContentAsString = @'
# Start SSH service in WSL
bash.exe -c "sudo /usr/sbin/service ssh start"
# Remove port proxy rule
netsh.exe interface portproxy delete v4tov4 listenport=2222 listenaddress=0.0.0.0 protocol=tcp
# Get IP address from WSL
$IP = (wsl.exe hostname -I).Trim()
# Add port proxy rule with the obtained IP address
netsh.exe interface portproxy add v4tov4 listenport=2222 listenaddress=0.0.0.0 connectport=2222 connectaddress=$IP
'@
$TaskName = "Start WSL SSHD on Boot"
$TaskUser = "ttadmin"
$ScriptContentAsString | Out-File -FilePath $ScriptOutputPath -Encoding ascii -Force
$TenSecondsFromNow = $(Get-Date).Add($(New-TimeSpan -Seconds 10))
$TaskTrigger = New-ScheduledTaskTrigger -AtStartup
$Options = New-ScheduledTaskSettingsSet -MultipleInstances IgnoreNew -WakeToRun -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -ExecutionTimeLimit $(New-TimeSpan -Hours 1)
$Passwd = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR((Read-Host -Prompt "Enter password" -AsSecureString)))
$Action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -Command `"& $ScriptOutputPath`""
Register-ScheduledTask -TaskName $TaskName -Trigger $TaskTrigger -Settings $Options -User $TaskUser -Password $Passwd -Action $Action -ErrorAction Stop
#>

# OPTIONAL 2: Install Windows Subsystem for Android
# NOTE: If the below $AppxUri doesn't work, you can get the latest version by navigating to https://store.rg-adguard.net/ and in the URL box, input: www.microsoft.com/en-us/p/windows-subsystem-for-android/9p3395vx91nr
<#
$AppxUri = 'http://tlu.dl.delivery.mp.microsoft.com/filestreamingservice/files/862fe146-d265-4305-9951-f8c5983f427d?P1=1689726418&P2=404&P3=2&P4=mHD%2fatoZ49xCdHZMGnivAxQwc0j86RlROyiL2pMGxg0%2fb6ezs9lPQYFHzQTTPcA9XkalD6focoDkR1%2bkSgKp2Q%3d%3d'
$OutFilePath = 'C:\Users\ttadmin\Downloads\windows_subsystem_for_android.msixbundle'
ssh -i $SSHPrivateKeyPath $SSHUserAndHost "pwsh.exe -ExecutionPolicy Bypass -Command `"Invoke-WebRequest -uri '$AppxUri' -OutFile '$OutFilePath'; dism.exe /Online /Add-ProvisionedAppxPackage /PackagePath:$OutFilePath /SkipLicense`""
#>

# OPTIONAL 3: Install TTYD
# Install TTYD and create scheduled task to run it as a specific user (i.e. the person who uses the PC most often)
<#
$CreateRemoteSchdTaskParams = @{
RemoteUserName = $RemoteUserName
RemoteIPAddress = $RemoteIPAddress
ModuleDir = "C:\Scripts\powershell"
SSHPrivateKeyPath = $SSHPrivateKeyPath
NetworkInterfaceAlias = "ZeroTier One [$ZTNetworkID]"
TaskUser = "ttadminbackup"
TTYDWebUser = "ttydadmin"
TTYDWebPassword = "MyP@ssword123!"
}
Create-RemoteTTYDScheduledTask @CreateRemoteSchdTaskParams
#>

# OPTIONAL 4: Prompt the remote user for a secure string
<#
Import-Module "$ScriptsDir\powershell\MiniServeModule.psm1"
# Make sure you have miniserve.exe on the local workstation
$NetworkInterfaceAlias = "ZeroTier One [$ZTNetworkID]"
Install-MiniServe -NetworkInterfaceAlias $NetworkInterfaceAlias
$PromptSSParams = @{
RemoteUserName = $RemoteUserName
RemoteIPAddress = $RemoteIPAddress
SSHPrivateKeyPath = $SSHPrivateKeyPath
MiniServeNetworkInterfaceAlias = $NetworkInterfaceAlias
RemovePwdFile = $False
}
$UserString = Prompt-ActiveUserForSecureString @PromptSSParams
#>

0 comments on commit a569ee3

Please sign in to comment.