471 lines
16 KiB
PowerShell
471 lines
16 KiB
PowerShell
#Abstract layer
|
|
Enum MachineRole {
|
|
Client
|
|
Server
|
|
}
|
|
|
|
Enum Protocol
|
|
{
|
|
WSMAN
|
|
SSH
|
|
}
|
|
|
|
Enum PlatformType {
|
|
Windows
|
|
Linux
|
|
OSX
|
|
}
|
|
|
|
function Set-Platform {
|
|
# Use the .NET Core APIs to determine the current platform; if a runtime
|
|
# exception is thrown, we are on FullCLR, not .NET Core.
|
|
try {
|
|
$Runtime = [System.Runtime.InteropServices.RuntimeInformation]
|
|
$OSPlatform = [System.Runtime.InteropServices.OSPlatform]
|
|
|
|
$IsLinux = $Runtime::IsOSPlatform($OSPlatform::Linux)
|
|
$IsOSX = $Runtime::IsOSPlatform($OSPlatform::OSX)
|
|
$IsWindows = $Runtime::IsOSPlatform($OSPlatform::Windows)
|
|
} catch {
|
|
try {
|
|
$IsLinux = $false
|
|
$IsOSX = $false
|
|
$IsWindows = $true
|
|
}
|
|
catch { }
|
|
}
|
|
if($IsOSX) {
|
|
[PlatformType]::OSX
|
|
} elseif($IsLinux) {
|
|
[PlatformType]::Linux
|
|
} else {
|
|
[PlatformType]::Windows
|
|
}
|
|
}
|
|
|
|
function Is-CoreCLR {
|
|
# Use the .NET Core APIs to determine the current platform; if a runtime
|
|
# exception is thrown, we are on FullCLR, not .NET Core.
|
|
try {
|
|
$Runtime = [System.Runtime.InteropServices.RuntimeInformation]
|
|
$IsCoreCLR = $true
|
|
} catch {
|
|
try {
|
|
$IsCoreCLR = $false
|
|
}
|
|
catch { }
|
|
}
|
|
if($IsCoreCLR)
|
|
{
|
|
$true
|
|
}
|
|
$false
|
|
}
|
|
|
|
Class Machine
|
|
{
|
|
[string] $MachineName = "localhost"
|
|
[MachineRole] $Role = [MachineRole]::Client
|
|
[PlatformType] $Platform
|
|
[boolean] $IsCoreCLR
|
|
|
|
#Members on server role
|
|
[string []] $PublicHostKeyPaths
|
|
[string []] $PrivateHostKeyPaths
|
|
[string] $ssouser = "sshtest_ssouser"
|
|
[string] $passwduser = "sshtest_passwduser"
|
|
[string] $passwduser_pw = "P@ssw0rd_1"
|
|
[string] $localAdminAuthorizedKeyPath
|
|
[string] $sshdConfigFile = (join-path $PSScriptRoot "sshd_config")
|
|
[string] $backupFileName = (join-path $PSScriptRoot "sshd_backup")
|
|
[System.Security.SecureString] $password
|
|
$preLatfpSetting
|
|
[string] $localUserprofilePath
|
|
|
|
#Members on client role
|
|
[string []] $clientPrivateKeyPaths
|
|
[string []] $clientPublicKeyPaths
|
|
[string] $ClientKeyDirectory
|
|
[string] $knownHostOfCurrentUser
|
|
[string] $OpenSSHdir = $PSScriptRoot
|
|
[string] $ToolsPath = "$env:ProgramData\chocolatey\lib\sysinternals\tools"
|
|
|
|
Machine() {
|
|
$this.Platform = Set-Platform
|
|
$this.IsCoreCLR = Is-CoreCLR
|
|
#$this.InitializeClient()
|
|
#$this.InitializeServer()
|
|
}
|
|
|
|
Machine ([MachineRole] $r) {
|
|
$this.Platform = Set-Platform
|
|
$this.IsCoreCLR = Is-CoreCLR
|
|
$this.Role = $r
|
|
#if($this.Role -eq [MachineRole]::Client) {
|
|
# $this.InitializeClient()
|
|
#} else {
|
|
# $this.InitializeServer()
|
|
#}
|
|
}
|
|
|
|
[void] InitializeClient() {
|
|
$this.ClientKeyDirectory = join-path $PSScriptRoot "clientkeys"
|
|
if(-not (Test-path $this.ClientKeyDirectory -PathType Container))
|
|
{
|
|
New-Item -Path $this.ClientKeyDirectory -ItemType Directory -Force -ErrorAction silentlycontinue
|
|
}
|
|
|
|
Remove-Item -Path "$($this.ClientKeyDirectory)\*" -Force -ea silentlycontinue
|
|
|
|
$this.knownHostOfCurrentUser = join-path ($env:USERPROFILE) ".ssh/known_hosts"
|
|
|
|
if ($this.Platform -eq [PlatformType]::Windows)
|
|
{
|
|
$this.ToolsPath = "$env:ProgramData\chocolatey\lib\sysinternals\tools"
|
|
#download pstools
|
|
if ( -not (Test-Path (join-path $($this.ToolsPath) "psexec.exe" ))) {
|
|
$this.DownloadPStools()
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
[void] InitializeServer() {
|
|
if ($this.Platform -eq [PlatformType]::Windows)
|
|
{
|
|
#Start-Service sshd
|
|
#load the profile to create the profile folder
|
|
$this.SetLocalAccountTokenFilterPolicy(1)
|
|
}
|
|
|
|
$this.password = ConvertTo-SecureString -String $this.localAdminPassword -AsPlainText -Force
|
|
$this.AddAdminUser($this.localAdminUserName, $this.password)
|
|
|
|
$this.SetupServerRemoting([Protocol]::WSMAN)
|
|
$this.localUserprofilePath = $this.GetUserProfileLocation($this)
|
|
$sshPath = join-path $($this.localUserprofilePath) ".ssh"
|
|
if(-not (Test-path $sshPath -PathType Container))
|
|
{
|
|
New-Item -Path $sshPath -ItemType Directory -Force -ErrorAction silentlycontinue
|
|
}
|
|
$this.localAdminAuthorizedKeyPath = join-path $($this.localUserprofilePath) ".ssh/authorized_keys"
|
|
Remove-Item -Path $($this.localAdminAuthorizedKeyPath) -Force -ea silentlycontinue
|
|
}
|
|
|
|
[void] SetupClient([Machine] $server) {
|
|
#add the host keys known host on client
|
|
|
|
if( -not (Test-Path $($this.knownHostOfCurrentUser ) ) )
|
|
{
|
|
$null = New-item -path $($this.knownHostOfCurrentUser) -force
|
|
}
|
|
foreach($keypath in $server.PublicHostKeyPaths)
|
|
{
|
|
$this.SetKeys($($server.MachineName), $keypath, $($this.knownHostOfCurrentUser))
|
|
}
|
|
}
|
|
|
|
[void] SetupSingleSignon([string] $identifyFile) {
|
|
.\ssh-add.exe $identifyFile
|
|
}
|
|
|
|
[void] CleanupSingleSignon([string] $identifyFile) {
|
|
.\ssh-add.exe -d $identifyFile
|
|
}
|
|
|
|
[void] AddItemInSSHDConfig([string] $key, [string] $value) {
|
|
if ( $this.Platform -eq [PlatformType]::Windows ) {
|
|
Get-Content $this.sshdConfigFile | % {
|
|
if($_.StartsWith($key)) {
|
|
"#$_"
|
|
}
|
|
else {$_}
|
|
} | Set-Content $this.sshdConfigFile
|
|
Add-Content -Path $this.sshdConfigFile -Value "`r`n$key $value"
|
|
|
|
Restart-Service sshd
|
|
} else {
|
|
}
|
|
}
|
|
|
|
[void] BackupSSHDConfig() {
|
|
if ( $this.Platform -eq [PlatformType]::Windows ) {
|
|
if(Test-path $this.backupFileName) {
|
|
Remove-Item -Path $this.backupFileName -Force
|
|
}
|
|
|
|
Copy-Item $this.sshdConfigFile $this.backupFileName -Force
|
|
}
|
|
}
|
|
|
|
[void] RestoreSSHDConfig() {
|
|
if ( $this.Platform -eq [PlatformType]::Windows ) {
|
|
Copy-Item $this.backupFileName $this.sshdConfigFile -Force
|
|
Remove-Item -Path $this.backupFileName -Force
|
|
Restart-Service sshd
|
|
}
|
|
}
|
|
|
|
[void] SetupServerRemoting([Protocol] $protocol) {
|
|
if ($this.Platform -eq [PlatformType]::Windows)
|
|
{
|
|
switch($protocol )
|
|
{
|
|
([Protocol]::SSH) {
|
|
$env:Path = "$env:Path;$PSScriptRoot"
|
|
Restart-Service sshd
|
|
}
|
|
([Protocol]::WSMAN) {
|
|
if( (Get-ComputerInfo).osproductType -notcontains 'Server' )
|
|
{
|
|
Enable-PSRemoting -Force
|
|
}
|
|
}
|
|
default {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
[void] SetupServer([Machine] $client) {
|
|
if( -not (Test-Path $($this.localAdminAuthorizedKeyPath ) ) )
|
|
{
|
|
$null = New-item -path $($this.localAdminAuthorizedKeyPath) -force
|
|
}
|
|
|
|
foreach($publicKeyPath in $client.clientPublicKeyPaths)
|
|
{
|
|
$this.SetKeys($null, $publicKeyPath, $($this.localAdminAuthorizedKeyPath))
|
|
}
|
|
# Provide Read Access to NT Service\sshd
|
|
$acl = get-acl $($this.localAdminAuthorizedKeyPath)
|
|
$ar = New-Object System.Security.AccessControl.FileSystemAccessRule("NT Service\sshd", "Read", "Allow")
|
|
$acl.SetAccessRule($ar)
|
|
Set-Acl $($this.localAdminAuthorizedKeyPath) $acl
|
|
}
|
|
|
|
[void] CleanupServer() {
|
|
$sshPath = split-path $this.localAdminAuthorizedKeyPath -Parent
|
|
if(Test-Path $sshPath -PathType Container )
|
|
{
|
|
Remove-item -path $sshPath -force -Recurse
|
|
}
|
|
|
|
if ( $this.Platform -eq [PlatformType]::Windows )
|
|
{
|
|
$this.CleanupLocalAccountTokenFilterPolicy()
|
|
}
|
|
}
|
|
|
|
[void] CleanupClient() {
|
|
Remove-item -path $($this.ClientKeyDirectory) -force -Recurse -ea silentlycontinue
|
|
$sshPath = split-path $this.knownHostOfCurrentUser -Parent
|
|
if(Test-Path $sshPath -PathType Container )
|
|
{
|
|
Remove-item -path $sshPath -force -Recurse
|
|
}
|
|
$this.CleanupPasswordSetting()
|
|
}
|
|
|
|
[void] RunCmd($Str) {
|
|
if ($this.Platform -eq [PlatformType]::Windows)
|
|
{
|
|
cmd /c $Str
|
|
}
|
|
}
|
|
|
|
[void] AddLocalUser($UserName, $password) {
|
|
$a = Get-LocalUser -Name $UserName -ErrorAction Ignore
|
|
if ($a -eq $null)
|
|
{
|
|
$pass = ConvertTo-SecureString -String $this.localAdminPassword -AsPlainText -Force
|
|
$a = New-LocalUser -Name $UserName -Password $pass -AccountNeverExpires -PasswordNeverExpires -UserMayNotChangePassword
|
|
}
|
|
}
|
|
|
|
[void] AddLocalGroup($groupName) {
|
|
$g = Get-LocalGroup -Name $groupName -ErrorAction Ignore
|
|
if ($g -eq $null)
|
|
{
|
|
$g = New-LocalGroup -Name $groupName
|
|
}
|
|
}
|
|
|
|
[void] AddUserToLocalGroup($UserName, $password, $groupName) {
|
|
if ( $this.Platform -eq [PlatformType]::Windows ) {
|
|
$this.AddLocalUser($UserName, $password)
|
|
$this.AddLocalGroup($groupName)
|
|
|
|
if((Get-LocalGroupMember -Name $groupName -Member $UserName -ErrorAction Ignore ) -eq $null)
|
|
{
|
|
Add-LocalGroupMember -Name $groupName -Member $UserName
|
|
}
|
|
} else {
|
|
#Todo add local user and add it to a user group on linux
|
|
}
|
|
}
|
|
|
|
[void] RemoveUserFromLocalGroup($UserName, $groupName) {
|
|
if ( $this.Platform -eq [PlatformType]::Windows ) {
|
|
if((Get-LocalGroupMember -Name $groupName -Member $UserName -ErrorAction Ignore ) -eq $null)
|
|
{
|
|
Remove-LocalGroupMember -Name $groupName -Member $UserName
|
|
}
|
|
} else {
|
|
#Todo add local user and add it to a user group on linux
|
|
}
|
|
}
|
|
|
|
[void] ClenaupLocalGroup($groupName) {
|
|
$g = Get-LocalGroup -Name $groupName -ErrorAction Ignore
|
|
if ($g -eq $null)
|
|
{
|
|
$g | Remove-LocalGroup
|
|
}
|
|
}
|
|
|
|
[void] AddAdminUser($UserName, $password) {
|
|
if ( $this.Platform -eq [PlatformType]::Windows ) {
|
|
$a = Get-LocalUser -Name $UserName -ErrorAction Ignore
|
|
if ($a -eq $null)
|
|
{
|
|
$a = New-LocalUser -Name $UserName -Password $password -AccountNeverExpires -PasswordNeverExpires -UserMayNotChangePassword
|
|
}
|
|
|
|
if((Get-LocalGroupMember -SID s-1-5-32-544 -Member $a -ErrorAction Ignore ) -eq $null)
|
|
{
|
|
Add-LocalGroupMember -SID s-1-5-32-544 -Member $a
|
|
}
|
|
} else {
|
|
#Todo add local user and add it to a administrators on linux
|
|
}
|
|
}
|
|
|
|
[void] AddPasswordSetting([string] $pass) {
|
|
if ($this.Platform -eq [PlatformType]::Windows) {
|
|
if (-not($env:DISPLAY)) {$env:DISPLAY=1}
|
|
$env:SSH_ASKPASS="$($env:ComSpec) /c echo $pass"
|
|
}
|
|
}
|
|
|
|
[void] CleanupPasswordSetting() {
|
|
if ($this.Platform -eq [PlatformType]::Windows -and (Test-Path env:SSH_ASKPASS))
|
|
{
|
|
if ($env:DISPLAY -eq 1) {Remove-Item env:\DISPLAY}
|
|
remove-item "env:SSH_ASKPASS" -ErrorAction SilentlyContinue
|
|
}
|
|
}
|
|
|
|
#Set LocalAccountTokenFilterPolicy
|
|
[void] SetLocalAccountTokenFilterPolicy($setting) {
|
|
$path = "HKLM:\Software\Microsoft\Windows\CurrentVersion\Policies\system"
|
|
#load the profile to create the profile folder
|
|
$this.preLatfpSetting = get-ItemProperty -Path $path -Name LocalAccountTokenFilterPolicy -ErrorAction Ignore
|
|
if( $this.preLatfpSetting -eq $null)
|
|
{
|
|
New-ItemProperty -Path $path -Name LocalAccountTokenFilterPolicy -Value $setting -PropertyType DWord
|
|
}
|
|
else
|
|
{
|
|
Set-ItemProperty -Path $path -Name LocalAccountTokenFilterPolicy -Value $setting
|
|
}
|
|
}
|
|
|
|
[void] CleanupLocalAccountTokenFilterPolicy() {
|
|
if($this.preLatfpSetting -eq $null)
|
|
{
|
|
Remove-ItemProperty -Path HKLM:\Software\Microsoft\Windows\CurrentVersion\Policies\system -Name LocalAccountTokenFilterPolicy -Force -ErrorAction SilentlyContinue
|
|
}
|
|
else
|
|
{
|
|
Set-ItemProperty -Path HKLM:\Software\Microsoft\Windows\CurrentVersion\Policies\system -Name LocalAccountTokenFilterPolicy -Value $this.preLatfpSetting.LocalAccountTokenFilterPolicy
|
|
}
|
|
}
|
|
|
|
[void] SecureHostKeys([string[]] $keys) {
|
|
if ( $this.Platform -eq [PlatformType]::Windows )
|
|
{
|
|
#TODO: Remove the path to OpenSSHDir from the string link
|
|
#Secure host-keys with psexec
|
|
foreach($key in $keys) {
|
|
& "$($this.ToolsPath)\psexec" -accepteula -nobanner -i -s -w $($this.OpenSSHdir) cmd.exe /c "ssh-add.exe $key"
|
|
}
|
|
}
|
|
}
|
|
|
|
[void] CleanupHostKeys() {
|
|
if ( $this.Platform -eq [PlatformType]::Windows )
|
|
{
|
|
& "$($this.ToolsPath)\psexec" -accepteula -nobanner -i -s -w $($this.OpenSSHdir) cmd.exe /c "ssh-add.exe -D"
|
|
}
|
|
}
|
|
|
|
[string] GetUserProfileLocation([Machine] $remote ) {
|
|
#load the profile to create the profile folder
|
|
$pscreds = [System.Management.Automation.PSCredential]::new($($remote.MachineName) + "\" + $($remote.localAdminUserName), $($remote.password))
|
|
$ret = Invoke-Command -Credential $pscreds -ComputerName $($remote.MachineName) -command {$env:userprofile}
|
|
return $ret
|
|
}
|
|
|
|
[void] UnzipFile($argVar, $targetondisk ) {
|
|
$shell_app=new-object -com shell.application
|
|
$zip_file = $shell_app.namespace($argVar)
|
|
Write-Host "Uncompressing zip file to $($targetondisk)" -ForegroundColor Cyan
|
|
$destination = $shell_app.namespace($targetondisk)
|
|
$destination.Copyhere($zip_file.items(), 0x10)
|
|
$shell_app = $null
|
|
}
|
|
|
|
#this does not work when "using module"; works fine when import the module
|
|
[void] DownloadPStools()
|
|
{
|
|
$machinePath = [Environment]::GetEnvironmentVariable('Path', 'MACHINE')
|
|
$newMachineEnvironmentPath = $machinePath
|
|
# Install chocolatey
|
|
$chocolateyPath = "$env:AllUsersProfile\chocolatey\bin"
|
|
if(Get-Command "choco" -ErrorAction SilentlyContinue)
|
|
{
|
|
Write-Information -MessageData "Chocolatey is already installed. Skipping installation."
|
|
}
|
|
else
|
|
{
|
|
Write-Information -MessageData "Chocolatey not present. Installing chocolatey."
|
|
Invoke-Expression ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))
|
|
|
|
if (-not ($machinePath.ToLower().Contains($chocolateyPath.ToLower())))
|
|
{
|
|
Write-Information -MessageData "Adding $chocolateyPath to Path environment variable"
|
|
$newMachineEnvironmentPath += ";$chocolateyPath"
|
|
$env:Path += ";$chocolateyPath"
|
|
}
|
|
else
|
|
{
|
|
Write-Information -MessageData "$chocolateyPath already present in Path environment variable"
|
|
}
|
|
}
|
|
|
|
if ( -not (Test-Path $($this.ToolsPath) ) ) {
|
|
Write-Information -MessageData "sysinternals not present. Installing sysinternals."
|
|
choco install sysinternals -y
|
|
}
|
|
else
|
|
{
|
|
Write-Information -MessageData "sysinternals present. Skipping installation."
|
|
}
|
|
}
|
|
|
|
[void] SetKeys($Hostnames, $keyPath, $Path) {
|
|
if($Hostnames -ne $null)
|
|
{
|
|
foreach ($hostname in $Hostnames)
|
|
{
|
|
($hostname + " " + (Get-Content $keyPath)) | Out-File -Append $Path -Encoding ascii
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Get-Content $keyPath | Out-File -Append $Path -Encoding ascii
|
|
}
|
|
}
|
|
}
|