Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
HelpersRemoting.psm1663 linesDownload Raw Back to HelpersRemoting
1# Copyright (c) Microsoft Corporation.2# Licensed under the MIT License.3 4##5## WinRM Remoting helper functions for writing remoting tests6##7 8$Script:CIRemoteCred = $null9 10if ($IsWindows) {11    try { $Script:CIRemoteCred = Import-Clixml -Path "$env:TEMP\CIRemoteCred.xml" } catch { }12}13 14function Get-DefaultEndPointName15{16    $endPointName = "PowerShell.$(${PSVersionTable}.GitCommitId)"17    $endPoint = Get-PSSessionConfiguration -Name $endPointName -ErrorAction SilentlyContinue18 19    if ($endPoint -eq $null)20    {21        $null = Enable-PSRemoting -SkipNetworkProfileCheck22        $endPoint = Get-PSSessionConfiguration -Name $endPointName -ErrorAction SilentlyContinue23 24        if ($endPoint -eq $null)25        {26            Write-Warning "Unable to create the remoting configuration endpoint for this PowerShell version: $(${PSVersionTable}.PSVersion)"27            return $endPointName28        }29    }30 31    if ($endPoint.Permission -like "*NT AUTHORITY\NETWORK AccessDenied*")32    {33        $null = Enable-PSRemoting -SkipNetworkProfileCheck34        $endPoint = Get-PSSessionConfiguration -Name $endPointName -ErrorAction SilentlyContinue35 36        if ($endPoint.Permission -like "*NT AUTHORITY\NETWORK AccessDenied*")37        {38            Write-Warning "Unable to enable the remoting configuration endpoint: $(${PSVersionTable}.PSVersion)"39        }40    }41 42    return $endPointName43}44 45function New-RemoteRunspace46{47    param (48        [string] $ConfigurationName49    )50 51    # For PSCore6, we want to always test against a remoting endpoint running PSCore6 (not Windows PowerShell)52    if ([string]::IsNullOrEmpty($ConfigurationName))53    {54        $ConfigurationName = Get-DefaultEndPointName55    }56 57    $wsmanConInfo = [System.Management.Automation.Runspaces.WSManConnectionInfo]::new()58 59    $wsmanConInfo.ShellUri = 'http://schemas.microsoft.com/powershell/' + $ConfigurationName60 61    if ($Script:CIRemoteCred)62    {63        Write-Verbose "Using Global CI Credential" -Verbose64        $wsmanConInfo.Credential = $Script:CIRemoteCred65    }66    else67    {68        Write-Verbose "Using Implicit Credential" -Verbose69    }70 71    $remoteRunspace = [runspacefactory]::CreateRunspace($Host, $wsmanConInfo)72    $remoteRunspace.Open()73 74    Write-Verbose "Successfully created remote runspace on endpoint: $ConfigurationName"75 76    return $remoteRunspace77}78 79function New-RemoteRunspacePool80{81    param (82        [int] $MinRunspace = 1,83 84        [int] $MaxRunspace = 6,85 86        [string] $ConfigurationName87    )88 89    $wsmanConnection = [System.Management.Automation.Runspaces.WSManConnectionInfo]::new()90 91    if ($ConfigurationName -ne $null)92    {93        $wsmanConnection.ShellUri = "http://schemas.microsoft.com/powershell/$ConfigurationName"94    }95 96    if ($Script:CIRemoteCred)97    {98        Write-Verbose "Using Global CI Credential" -Verbose99        $wsmanConnection.Credential = $Script:CIRemoteCred100    }101    else102    {103        Write-Verbose "Using Implicit Credential" -Verbose104    }105 106    [System.Management.Automation.Runspaces.RunspacePool] $remoteRunspacePool = [runspacefactory]::CreateRunspacePool($MinRunspace, $MaxRunspace, $wsmanConnection)107    $remoteRunspacePool.Open()108 109    return $remoteRunspacePool110}111 112function CreateParameters113{114    param (115        [string] $ComputerName,116        [string[]] $Name,117        [string] $ConfigurationName,118        [switch] $CimSession,119        [System.Management.Automation.Remoting.PSSessionOption] $SessionOption,120        [System.Management.Automation.Runspaces.PSSession[]] $Session)121 122    if($ComputerName)123    {124        $parameters = @{ComputerName = $ComputerName}125    }126    else127    {128        if($Session)129        {130            $parameters = @{Session = $Session}131        }132        else133        {134            $parameters = @{ComputerName = '.'}135        }136    }137 138    if ($Name) {139        if($CimSession.IsPresent)140        {141            $parameters["Name"] = [String] $Name142        }143        else144        {145            $parameters["Name"] = $Name146        }147    }148 149    if ($ConfigurationName) {150        $parameters["ConfigurationName"] = $ConfigurationName151    }152 153    if ($SessionOption) {154        $parameters["SessionOption"] = $SessionOption155    }156 157    ## If a PSSession is provided, do not add credentials.158    if ($Script:CIRemoteCred -and (-not $Session))159    {160        Write-Verbose "Using Global CI Credential" -Verbose161        $parameters["Credential"] = $Script:CIRemoteCred162    }163    else164    {165        Write-Verbose "Using Implicit Credential" -Verbose166    }167 168    return $parameters169}170 171function New-RemoteSession172{173    param (174        [string] $Name,175        [string] $ConfigurationName,176        [switch] $CimSession,177        [System.Management.Automation.Remoting.PSSessionOption] $SessionOption178    )179 180    # For PSCore6, we want to always test against a remoting endpoint running PSCore6 (not Windows PowerShell)181    if ([string]::IsNullOrEmpty($ConfigurationName))182    {183        $ConfigurationName = Get-DefaultEndPointName184    }185 186    $parameters = CreateParameters -Name $Name -ConfigurationName $ConfigurationName -SessionOption $SessionOption -CimSession:$CimSession.IsPresent187 188    if ($CimSession) {189        $session = New-CimSession @parameters190    } else {191        $session = New-PSSession @parameters192    }193 194    Write-Verbose "Successfully created remote PSSession on endpoint: $ConfigurationName"195 196    return $session197}198 199function Invoke-RemoteCommand200{201    param (202        [string] $ComputerName,203        [scriptblock] $ScriptBlock,204        [string] $ConfigurationName,205        [switch] $InDisconnectedSession206    )207 208    # For PSCore6, we want to always test against a remoting endpoint running PSCore6 (not Windows PowerShell)209    if ([string]::IsNullOrEmpty($ConfigurationName))210    {211        $ConfigurationName = Get-DefaultEndPointName212    }213 214    $parameters = CreateParameters -ComputerName $ComputerName -ConfigurationName $ConfigurationName215 216    if($ScriptBlock)217    {218        $parameters.Add('ScriptBlock', $ScriptBlock)219    }220 221    if($InDisconnectedSession)222    {223        $parameters.Add('InDisconnectedSession', $InDisconnectedSession.IsPresent)224    }225 226    Invoke-Command @parameters227}228 229function Enter-RemoteSession230{231    param(232        [string] $Name,233        [string] $ConfigurationName,234        [System.Management.Automation.Remoting.PSSessionOption] $SessionOption)235 236    $parameters = CreateParameters -Name $Name -ConfigurationName $ConfigurationName -SessionOption $SessionOption237    Enter-PSSession @parameters238}239 240function Connect-RemoteSession241{242    param(243        [string] $ComputerName,244        [string[]] $Name,245        [System.Management.Automation.Runspaces.PSSession[]] $Session,246        [string] $ConfigurationName247    )248 249    $parameters = CreateParameters -ComputerName $ComputerName -Name $Name -Session $Session -ConfigurationName $ConfigurationName250    Connect-PSSession @parameters251}252 253function Get-PipePath {254    param (255        $PipeName256    )257    if ($IsWindows) {258        return "\\.\pipe\$PipeName"259    }260    "$([System.IO.Path]::GetTempPath())CoreFxPipe_$PipeName"261}262 263##264## SSH Remoting helper functions for writing remoting tests265##266 267function Get-WindowsOpenSSHLink268{269    # From the Win OpenSSH Wiki page (https://github.com/PowerShell/Win32-OpenSSH/wiki/How-to-retrieve-links-to-latest-packages)270    $origSecurityProtocol = [Net.ServicePointManager]::SecurityProtocol271    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12272    try273    {274        $url = 'https://github.com/PowerShell/Win32-OpenSSH/releases/latest/'275        $request = [System.Net.WebRequest]::Create($url)276        $request.AllowAutoRedirect = $false277        $response = & { $request.GetResponse() } 2>$null278 279        if ($null -ne $response)280        {281            $location = [string] $response.GetResponseHeader("Location")282            if (! [string]::IsNullOrEmpty($location))283            {284                return $location.Replace('tag', 'download') + '/OpenSSH-Win64.zip'285            }286        }287    }288    finally289    {290        [Net.ServicePointManager]::SecurityProtocol = $origSecurityProtocol291    }292 293    # Default to last known latest release294    Write-Warning "Unable to get latest OpenSSH release link. Using default release link."295    return 'https://github.com/PowerShell/Win32-OpenSSH/releases/download/v8.1.0.0p1-Beta/OpenSSH-Win64.zip'296}297 298function Install-WindowsOpenSSH299{300    param (301        [switch] $Force302    )303 304    $destPath = Join-Path -Path $env:ProgramFiles -ChildPath 'OpenSSH-Win64'305    if (Test-Path -Path $destPath)306    {307        if (! $Force)308        {309            Write-Verbose -Verbose "OpenSSH-Win64 already exists, skipping install step"310            return311        }312 313        Write-Verbose -Verbose "Force re-install OpenSSH-Win64 ..."314        Stop-Service -Name sshd -ErrorAction SilentlyContinue315        Remove-Item -Path $destPath -Recurse -Force316    }317 318    # Get link to latest OpenSSH release319    Write-Verbose -Verbose "Downloading latest OpenSSH-Win64 package link ..."320    $downLoadLink = Get-WindowsOpenSSHLink321 322    # Download and extract OpenSSH package323    Write-Verbose -Verbose "Downloading OpenSSH-Win64 zip package ..."324    $packageFilePath = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath 'OpenSSH-Win64.zip'325    $oldProgressPreference = $ProgressPreference326    $ProgressPreference = 'SilentlyContinue'327    try328    {329        Invoke-WebRequest -Uri $downLoadLink -OutFile $packageFilePath330        Expand-Archive -Path $packageFilePath -DestinationPath $env:ProgramFiles331    }332    finally333    {334        $ProgressPreference = $oldProgressPreference335    }336 337    # Install and start SSHD service338    Push-Location $destPath339    try340    {341        Write-Verbose -Verbose "Running install-sshd.ps1 ..."342        .\install-sshd.ps1343 344        $netRule = Get-NetFirewallRule -Name sshd -ErrorAction SilentlyContinue345        if ($null -eq $netRule)346        {347            Write-Verbose -Verbose "Creating firewall rule for SSHD ..."348            New-NetFirewallRule -Name sshd -DisplayName "OpenSSH Server (sshd)" -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22349        }350 351        Write-Verbose -Verbose "Starting SSHD service ..."352        Restart-Service -Name sshd353    }354    finally355    {356        Pop-Location357    }358 359    # Current release of Windows OpenSSH configures SSHD to change AuthorizedKeyFiles for administrators360    # Comment it out so that normal key based authentication works per user as with Linux platforms.361    # Match Group administrators362    #       AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys363    $sshdFilePath = "$env:ProgramData\ssh\sshd_config"364    $sshdContent = Get-Content $sshdFilePath365    $sshdNewContent = [string[]] @()366    $modified = $false367    foreach ($item in $sshdContent)368    {369        if ($item.TrimStart().StartsWith('Match Group administrators') -or370            $item.TrimStart().StartsWith('AuthorizedKeysFile __PROGRAMDATA'))371        {372            if (!$modified) { $modified = $true }373            $sshdNewContent += "#" + $item374        }375        else376        {377            $sshdNewContent += $item378        }379    }380    if ($modified)381    {382        $sshdNewContent | Set-Content -Path $sshdFilePath -Force383    }384}385 386function Install-SSHRemotingOnWindows387{388    param (389        [Parameter(Mandatory=$true)]390        [string] $PowerShellPath391    )392 393    # Install sshd service394    if ($null -eq (Get-Command -Name sshd -ErrorAction SilentlyContinue))395    {396        Write-Verbose -Verbose "Installing SSHD service ..."397        Install-WindowsOpenSSH -Force398    }399 400    if (! (Test-Path -Path "$env:ProgramData\ssh\sshd_config"))401    {402        throw "Unable to install SSH service.  Config file $env:ProgramData\ssh\sshd_config does not exist."403    }404 405    # Configure SSH to authenticate with keys for this user.406    # PubkeyAuthentication should be enabled by default.407    # RSA keys should be enabled by default.408 409    # Create user .ssh directory.410    if (! (Test-Path -Path "$HOME\.ssh"))411    {412        Write-Verbose -Verbose "Creating $HOME\.ssh directory ..."413        New-Item -Path "$HOME\.ssh" -ItemType Directory -Force414    }415 416    # Create new rsa keys for current user.417    if ( !(Test-Path "$HOME\.ssh\id_rsa"))418    {419        Write-Verbose -Verbose "Creating rsa keys ..."420        cmd /c "ssh-keygen -t rsa -f $HOME\.ssh\id_rsa -q -N `"`""421    }422    if (! (Test-Path "$HOME\.ssh\id_rsa"))423    {424        throw "id_rsa private key file was not created."425    }426    if (! (Test-Path "$HOME\.ssh\id_rsa.pub"))427    {428        throw "id_rsa.pub public key file was not created."429    }430 431    # Create authorized keys file.432    Write-Verbose -Verbose "Creating authorized_keys ..."433    Get-Content -Path "$HOME\.ssh\id_rsa.pub" | Set-Content -Path "$HOME\.ssh\authorized_keys" -Force434 435    # Create known_hosts file for 'localhost' connection.436    Write-Verbose -Verbose "Creating known_hosts ..."437    ssh-keyscan -H localhost | Set-Content -Path "$HOME\.ssh\known_hosts" -Force438 439    # Install Microsoft.PowerShell.RemotingTools module.440    if ($null -eq (Get-Module -Name Microsoft.PowerShell.RemotingTools -ListAvailable))441    {442        Write-Verbose -Verbose "Installing Microsoft.PowerShell.RemotingTools ..."443        Install-Module -Name Microsoft.PowerShell.RemotingTools -Force -SkipPublisherCheck444    }445 446    # Add PowerShell endpoint to SSHD.447    Write-Verbose -Verbose "Running Enable-SSHRemoting ..."448    Enable-SSHRemoting -SSHDConfigFilePath "$env:ProgramData\ssh\sshd_config" -PowerShellFilePath $PowerShellPath -Force449 450    Write-Verbose -Verbose "Restarting sshd service ..."451    Restart-Service -Name sshd452 453    # Test SSH remoting.454    Write-Verbose -Verbose "Testing SSH remote connection ..."455    $session = New-PSSession -HostName localhost456    try457    {458        if ($null -eq $session)459        {460            throw "Could not successfully create SSH remoting connection."461        }462    }463    finally464    {465        Remove-PSSession $session466    }467}468 469function WriteVerboseSSHDStatus470{471    param (472        [string] $Msg = 'SSHD service status'473    )474 475    $sshdStatus = sudo service ssh status476    Write-Verbose -Verbose "${Msg}: $sshdStatus"477}478 479function DumpTextFile480{481    param (482        [string] $FilePath = '/etc/ssh/sshd_config'483    )484 485    $content = Get-Content -Path $FilePath -Raw486    Write-Verbose -Verbose $content487}488 489function Install-SSHRemotingOnLinux490{491    param (492        [Parameter(Mandatory=$true)]493        [string] $PowerShellPath494    )495 496    # Install ssh daemon.497    if (! (Test-Path -Path /etc/ssh/sshd_config))498    {499        Write-Verbose -Verbose "Installing openssh-server ..."500        sudo apt-get install --yes openssh-server501 502        Write-Verbose -Verbose "Restarting sshd service after install ..."503        WriteVerboseSSHDStatus "SSHD service status before restart"504        sudo service ssh restart505        WriteVerboseSSHDStatus "SSHD service status after restart"506    }507    if (! (Test-Path -Path /etc/ssh/sshd_config))508    {509        throw "Unable to install SSH daemon.  Config file /etc/ssh/sshd_config does not exist."510    }511 512    # Configure SSH to authenticate with keys for this user.513    # PubkeyAuthentication should be enabled by default.514    # RSA keys should be enabled by default.515 516    # Create user .ssh directory.517    if (! (Test-Path -Path "$HOME/.ssh"))518    {519        Write-Verbose -Verbose "Creating $HOME/.ssh directory ..."520        New-Item -Path "$HOME/.ssh" -ItemType Directory -Force521    }522 523    # Create new rsa keys for current user.524    if ( !(Test-Path "$HOME/.ssh/id_rsa"))525    {526        Write-Verbose -Verbose "Creating rsa keys ..."527        bash -c "ssh-keygen -t rsa -f $HOME/.ssh/id_rsa -q -N ''"528    }529    if (! (Test-Path "$HOME/.ssh/id_rsa"))530    {531        throw "id_rsa private key file was not created."532    }533    if (! (Test-Path "$HOME/.ssh/id_rsa.pub"))534    {535        throw "id_rsa.pub public key file was not created."536    }537 538    # Create authorized keys file.539    Write-Verbose -Verbose "Creating authorized_keys ..."540    Get-Content -Path "$HOME/.ssh/id_rsa.pub" | Set-Content -Path "$HOME/.ssh/authorized_keys" -Force541 542    # Create known_hosts file for 'localhost' connection.543    Write-Verbose -Verbose "Updating known_hosts ..."544    ssh-keyscan -H localhost | Set-Content -Path "$HOME/.ssh/known_hosts" -Force545 546    <#547    # Install Microsoft.PowerShell.RemotingTools module.548    if ($null -eq (Get-Module -Name Microsoft.PowerShell.RemotingTools -ListAvailable))549    {550        Write-Verbose -Verbose "Installing Microsoft.PowerShell.RemotingTools ..."551        Install-Module -Name Microsoft.PowerShell.RemotingTools -Force -SkipPublisherCheck552    }553    #>554 555    # Add PowerShell endpoint to SSHD.556    Write-Verbose -Verbose "Running Enable-SSHRemoting ..."557    Write-Verbose -Verbose "PSScriptRoot: $PSScriptRoot"558    $modulePath = "${PSScriptRoot}\..\Microsoft.PowerShell.RemotingTools\Microsoft.PowerShell.RemotingTools.psd1"559    $sshdFilePath = '/etc/ssh/sshd_config'560 561    # First create a default 'powershell' named endpoint.562    $cmdLine = "Import-Module ${modulePath}; Enable-SSHRemoting -SSHDConfigFilePath $sshdFilePath -PowerShellFilePath $PowerShellPath -Force"563    Write-Verbose -Verbose "CmdLine: $cmdLine"564    sudo pwsh -c $cmdLine565 566    # Next create a 'pwshconfig' named configured endpoint.567    # Configuration file:568    $configFilePath = Join-Path -Path "$env:HOME" -ChildPath 'PSTestConfig.pssc'569    '@{570        GUID = "4d667b90-25f8-47d5-9c90-619b27954748"571        Author = "Microsoft"572        Description = "Test local PowerShell session configuration"573        LanguageMode = "ConstrainedLanguage"574    }' | Out-File -FilePath $configFilePath575    $cmdLine = "Import-Module ${modulePath}; Enable-SSHRemoting -SSHDConfigFilePath $sshdFilePath -PowerShellFilePath $PowerShellPath -ConfigFilePath $configFilePath -SubsystemName 'pwshconfig' -Force"576    Write-Verbose -Verbose "CmdLine: $cmdLine"577    sudo pwsh -c $cmdLine578 579    # Finally create a 'pwshbroken' named configured endpoint.580    $cmdLine = "Import-Module ${modulePath}; Enable-SSHRemoting -SSHDConfigFilePath $sshdFilePath -PowerShellFilePath $PowerShellPath -ConfigFilePath '$HOME/NoSuch.pssc' -SubsystemName 'pwshbroken' -Force"581    Write-Verbose -Verbose "CmdLine: $cmdLine"582    sudo pwsh -c $cmdLine583 584    # Restart SSHD service for changes to take effect.585    Start-Sleep -Seconds 1586    WriteVerboseSSHDStatus "SSHD service status before restart"587    Write-Verbose -Verbose "Restarting sshd ..."588    sudo service ssh restart589    WriteVerboseSSHDStatus "SSHD service status after restart"590 591    # Try starting again if needed.592    $status = sudo service ssh status593    $result = $status | Where-Object { ($_ -like '*not running*') -or ($_ -like '*stopped*') }594    if ($null -ne $result)595    {596        Start-Sleep -Seconds 1597        Write-Verbose -Verbose "Starting sshd again ..."598        sudo service ssh start599        WriteVerboseSSHDStatus "SSHD service status after second start attempt"600    }601 602    # Test SSH remoting.603    Write-Verbose -Verbose "Testing SSH remote connection ..."604    $session = New-PSSession -HostName localhost605    try606    {607        if ($null -eq $session)608        {609            throw "Could not successfully create SSH remoting connection."610        }611        else612        {613            Write-Verbose -Verbose "SUCCESS: SSH remote connection"614        }615    }616    finally617    {618        Remove-PSSession $session619    }620}621 622<#623.Synopsis624    Installs and configures SSH components, and creates an SSH PowerShell remoting endpoint.625.Description626    This cmdlet assumes SSH client is installed on the machine, but will check for SSHD service and627    install it if needed.628    Next, it will configure SSHD for key based user authentication, for the current user context.629    Then it configures SSHD for a PowerShell endpoint based on the provided PowerShell file path.630    If no PowerShell file path is provided, the current PowerShell instance ($PSHOME) is used.631    Finally, it will test the new SSH remoting endpoint connection to ensure it works.632    Currently, only Ubuntu and Windows platforms are supported.633.Parameter PowerShellPath634    Specifies a PowerShell, pwsh(.exe), executable path that will be used for the remoting endpoint.635#>636function Install-SSHRemoting637{638    param (639        [string] $PowerShellFilePath640    )641 642    Write-Verbose -Verbose "Install-SSHRemoting called with PowerShell file path: $PowerShellFilePath"643 644    if ($IsWindows)645    {646        if ([string]::IsNullOrEmpty($PowerShellFilePath)) { $PowerShellFilePath = "$PSHOME/pwsh.exe" }647        Install-SSHRemotingOnWindows -PowerShellPath $PowerShellFilePath648        return649    }650    elseif ($IsLinux)651    {652        $LinuxInfo = Get-Content /etc/os-release -Raw | ConvertFrom-StringData653        if ($LinuxInfo.ID -match 'ubuntu')654        {655            if ([string]::IsNullOrEmpty($PowerShellFilePath)) { $PowerShellFilePath = "$PSHOME/pwsh" }656            Install-SSHRemotingOnLinux -PowerShellPath $PowerShellFilePath657            return658        }659    }660 661    Write-Error "Platform not supported.  Only Windows and Ubuntu plaforms are currently supported."662}663