src/Installer.ps1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# Allows for overriding of module path during test.
$ModuleBasePath = Convert-Path $PSScriptRoot\..

<#
.SYNOPSIS
    Configures your PowerShell profile (startup) script to import the posh-sshell
    module when PowerShell starts.
.DESCRIPTION
    Checks if your PowerShell profile script is not already importing posh-sshell
    and if not, adds a command to import the posh-sshell module. This will cause
    PowerShell to load posh-sshell whenever PowerShell starts.
.PARAMETER AllHosts
    By default, this command modifies the CurrentUserCurrentHost profile
    script. By specifying the AllHosts switch, the command updates the
    CurrentUserAllHosts profile (or AllUsersAllHosts, given -AllUsers).
.PARAMETER AllUsers
    By default, this command modifies the CurrentUserCurrentHost profile
    script. By specifying the AllUsers switch, the command updates the
    AllUsersCurrentHost profile (or AllUsersAllHosts, given -AllHosts).
    Requires elevated permissions.
.PARAMETER Force
    Do not check if the specified profile script is already importing
    posh-sshell. Just add Import-Module posh-sshell command.
.PARAMETER StartSshAgent
    Also add `Start-SshAgent -Quiet` to the specified profile script.
.EXAMPLE
    PS C:\> Add-PoshSshellToProfile
    Updates your profile script for the current PowerShell host to import the
    posh-sshell module when the current PowerShell host starts.
.EXAMPLE
    PS C:\> Add-PoshSshellToProfile -AllHosts
    Updates your profile script for all PowerShell hosts to import the posh-sshell
    module whenever any PowerShell host starts.
.INPUTS
    None.
.OUTPUTS
    None.
#>

function Add-PoshSshellToProfile {
  [CmdletBinding(SupportsShouldProcess)]
  param(
      [Parameter()]
      [switch]
      $AllHosts,

      [Parameter()]
      [switch]
      $AllUsers,

      [Parameter()]
      [switch]
      $Force,

      [Parameter()]
      [switch]
      $StartSshAgent,

      [Parameter(ValueFromRemainingArguments)]
      [psobject[]]
      $TestParams
  )

  if ($AllUsers -and !(Test-Administrator)) {
      throw 'Adding posh-sshell to an AllUsers profile requires an elevated host.'
  }

  $underTest = $false

  $profileName = $(if ($AllUsers) { 'AllUsers' } else { 'CurrentUser' }) `
               + $(if ($AllHosts) { 'AllHosts' } else { 'CurrentHost' })
  Write-Verbose "`$profileName = '$profileName'"

  $profilePath = $PROFILE.$profileName
  Write-Verbose "`$profilePath = '$profilePath'"

  # Under test, we override some variables using $args as a backdoor.
  if (($TestParams.Count -gt 0) -and ($TestParams[0] -is [string])) {
      $profilePath = [string]$TestParams[0]
      $underTest = $true
      if ($TestParams.Count -gt 1) {
          $ModuleBasePath = [string]$TestParams[1]
      }
  }

  if (!$profilePath) { $profilePath = $PROFILE }

  if (!$Force) {
      # Search the user's profiles to see if any are using posh-sshell already, there is an extra search
      # ($profilePath) taking place to accomodate the Pester tests.
      $importedInProfile = Test-PoshSshImportedInScript $profilePath
      if (!$importedInProfile -and !$underTest) {
          $importedInProfile = Test-PoshSshImportedInScript $PROFILE
      }
      if (!$importedInProfile -and !$underTest) {
          $importedInProfile = Test-PoshSshImportedInScript $PROFILE.CurrentUserCurrentHost
      }
      if (!$importedInProfile -and !$underTest) {
          $importedInProfile = Test-PoshSshImportedInScript $PROFILE.CurrentUserAllHosts
      }
      if (!$importedInProfile -and !$underTest) {
          $importedInProfile = Test-PoshSshImportedInScript $PROFILE.AllUsersCurrentHost
      }
      if (!$importedInProfile -and !$underTest) {
          $importedInProfile = Test-PoshSshImportedInScript $PROFILE.AllUsersAllHosts
      }

      if ($importedInProfile) {
          Write-Warning "Skipping add of posh-sshell import to file '$profilePath'."
          Write-Warning "posh-sshell appears to already be imported in one of your profile scripts."
          Write-Warning "If you want to force the add, use the -Force parameter."
          return
      }
  }

  if (!$profilePath) {
      Write-Warning "Skipping add of posh-sshell import to profile; no profile found."
      Write-Verbose "`$PROFILE = '$PROFILE'"
      Write-Verbose "CurrentUserCurrentHost = '$($PROFILE.CurrentUserCurrentHost)'"
      Write-Verbose "CurrentUserAllHosts = '$($PROFILE.CurrentUserAllHosts)'"
      Write-Verbose "AllUsersCurrentHost = '$($PROFILE.AllUsersCurrentHost)'"
      Write-Verbose "AllUsersAllHosts = '$($PROFILE.AllUsersAllHosts)'"
      return
  }

  # If the profile script exists and is signed, then we should not modify it
  if (Test-Path -LiteralPath $profilePath) {
      if (!(Get-Command Get-AuthenticodeSignature -ErrorAction SilentlyContinue)) {
          Write-Verbose "Platform doesn't support script signing, skipping test for signed profile."
      }
      else {
          $sig = Get-AuthenticodeSignature $profilePath
          if ($null -ne $sig.SignerCertificate) {
              Write-Warning "Skipping add of posh-sshell import to profile; '$profilePath' appears to be signed."
              Write-Warning "Add the command 'Import-Module posh-sshell' to your profile and resign it."
              return
          }
      }
  }

  # Check if the location of this module file is in the PSModulePath
  if (Test-InPSModulePath $ModuleBasePath) {
      $profileContent = "`nImport-Module posh-sshell"
  }
  else {
      $modulePath = Join-Path $ModuleBasePath posh-sshell.psd1
      $profileContent = "`nImport-Module '$modulePath'"
  }

  # Make sure the PowerShell profile directory exists
  $profileDir = Split-Path $profilePath -Parent
  if (!(Test-Path -LiteralPath $profileDir)) {
      if ($PSCmdlet.ShouldProcess($profileDir, "Create current user PowerShell profile directory")) {
          New-Item $profileDir -ItemType Directory -Force -Verbose:$VerbosePreference > $null
      }
  }

  if ($PSCmdlet.ShouldProcess($profilePath, "Add 'Import-Module posh-sshell' to profile")) {
      Add-Content -LiteralPath $profilePath -Value $profileContent -Encoding UTF8
  }

  if ($StartSshAgent -and $PSCmdlet.ShouldProcess($profilePath, "Add 'Start-SshAgent -Quiet' to profile")) {
    Add-Content -LiteralPath $profilePath -Value 'Start-SshAgent -Quiet' -Encoding UTF8
  }
}