|
5 | 5 |
|
6 | 6 | .DESCRIPTION |
7 | 7 | Connects to GitHub using a GitHub App to generate installation access tokens and create contexts for targets. |
| 8 | + This function supports recursive processing and parallel connections to multiple installations. |
8 | 9 |
|
9 | 10 | Available target types: |
10 | 11 | - User |
|
14 | 15 | .EXAMPLE |
15 | 16 | Connect-GitHubApp |
16 | 17 |
|
17 | | - Connects to GitHub as all available targets using the logged in GitHub App. |
| 18 | + Connects to GitHub as all available targets using the logged in GitHub App in parallel. |
18 | 19 |
|
19 | 20 | .EXAMPLE |
20 | 21 | Connect-GitHubApp -User 'octocat' |
|
31 | 32 |
|
32 | 33 | Connects to GitHub as the enterprise 'msx' using the logged in GitHub App. |
33 | 34 |
|
| 35 | + .EXAMPLE |
| 36 | + Get-GitHubAppInstallation | Connect-GitHubApp -ThrottleLimit 4 |
| 37 | +
|
| 38 | + Gets all app installations and connects to them in parallel with a maximum of 4 concurrent connections. |
| 39 | +
|
| 40 | + .EXAMPLE |
| 41 | + Connect-GitHubApp -User '*', -Organization 'psmodule', 'github' -ThrottleLimit 8 |
| 42 | +
|
| 43 | + Connects to all users and the specified organizations in parallel with a maximum of 8 concurrent connections. |
| 44 | +
|
34 | 45 | .NOTES |
35 | 46 | [Authenticating to the REST API](https://docs.github.com/rest/overview/other-authentication-methods#authenticating-for-saml-sso) |
36 | 47 |
|
|
41 | 52 | [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '', Justification = 'Is the CLI part of the module.')] |
42 | 53 | [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '', |
43 | 54 | Justification = 'The tokens are received as clear text. Mitigating exposure by removing variables and performing garbage collection.')] |
44 | | - [CmdletBinding(DefaultParameterSetName = '__AllParameterSets')] |
| 55 | + [CmdletBinding(DefaultParameterSetName = 'All Installations')] |
45 | 56 | param( |
46 | 57 | # The user account to connect to. |
47 | | - [Parameter(ParameterSetName = 'Filtered')] |
| 58 | + [Parameter(ParameterSetName = 'Filtered', ValueFromPipelineByPropertyName)] |
48 | 59 | [SupportsWildcards()] |
49 | 60 | [string[]] $User, |
50 | 61 |
|
51 | 62 | # The organization to connect to. |
52 | | - [Parameter(ParameterSetName = 'Filtered')] |
| 63 | + [Parameter(ParameterSetName = 'Filtered', ValueFromPipelineByPropertyName)] |
53 | 64 | [SupportsWildcards()] |
54 | 65 | [string[]] $Organization, |
55 | 66 |
|
56 | 67 | # The enterprise to connect to. |
57 | | - [Parameter(ParameterSetName = 'Filtered')] |
| 68 | + [Parameter(ParameterSetName = 'Filtered', ValueFromPipelineByPropertyName)] |
58 | 69 | [SupportsWildcards()] |
59 | 70 | [string[]] $Enterprise, |
60 | 71 |
|
| 72 | + # Installation objects from pipeline for parallel processing. |
| 73 | + [Parameter(Mandatory, ParameterSetName = 'Installation', ValueFromPipeline)] |
| 74 | + [GitHubAppInstallation[]] $Installation, |
| 75 | + |
| 76 | + # The maximum number of parallel operations to run at once. |
| 77 | + [Parameter(ParameterSetName = 'Filtered')] |
| 78 | + [Parameter(ParameterSetName = 'Installation')] |
| 79 | + [uint] $ThrottleLimit = ([Environment]::ProcessorCount * 2), |
| 80 | + |
61 | 81 | # Passes the context object to the pipeline. |
62 | 82 | [Parameter()] |
63 | 83 | [switch] $PassThru, |
|
82 | 102 | Write-Debug "[$stackPath] - Start" |
83 | 103 | $Context = Resolve-GitHubContext -Context $Context |
84 | 104 | Assert-GitHubContext -Context $Context -AuthType App |
| 105 | + $selectedInstallations = @() |
85 | 106 | } |
86 | 107 |
|
87 | 108 | process { |
88 | | - $installations = Get-GitHubAppInstallation -Context $Context |
89 | | - $selectedInstallations = @() |
90 | | - Write-Verbose "Found [$($installations.Count)] installations." |
91 | 109 | switch ($PSCmdlet.ParameterSetName) { |
| 110 | + 'Installation' { |
| 111 | + if ($Installation.Count -eq 1) { |
| 112 | + Write-Verbose "Processing installation [$($Installation.Target.Name)] [$($Installation.ID)]" |
| 113 | + $token = New-GitHubAppInstallationAccessToken -Context $Context -ID $Installation.ID |
| 114 | + |
| 115 | + $contextParams = @{ |
| 116 | + AuthType = [string]'IAT' |
| 117 | + TokenType = [string]'ghs' |
| 118 | + DisplayName = [string]$Context.DisplayName |
| 119 | + ApiBaseUri = [string]$Context.ApiBaseUri |
| 120 | + ApiVersion = [string]$Context.ApiVersion |
| 121 | + HostName = [string]$Context.HostName |
| 122 | + HttpVersion = [string]$Context.HttpVersion |
| 123 | + PerPage = [int]$Context.PerPage |
| 124 | + ClientID = [string]$Context.ClientID |
| 125 | + InstallationID = [string]$installation.ID |
| 126 | + Permissions = [GitHubPermission[]]$installation.Permissions |
| 127 | + Events = [string[]]$installation.Events |
| 128 | + InstallationType = [string]$installation.Type |
| 129 | + Token = [securestring]$token.Token |
| 130 | + TokenExpiresAt = [datetime]$token.ExpiresAt |
| 131 | + } |
| 132 | + |
| 133 | + switch ($installation.Type) { |
| 134 | + 'User' { |
| 135 | + $contextParams['InstallationName'] = [string]$installation.Target.Name |
| 136 | + $contextParams['Owner'] = [string]$installation.Target.Name |
| 137 | + } |
| 138 | + 'Organization' { |
| 139 | + $contextParams['InstallationName'] = [string]$installation.Target.Name |
| 140 | + $contextParams['Owner'] = [string]$installation.Target.Name |
| 141 | + } |
| 142 | + 'Enterprise' { |
| 143 | + $contextParams['InstallationName'] = [string]$installation.Target.Name |
| 144 | + $contextParams['Enterprise'] = [string]$installation.Target.Name |
| 145 | + } |
| 146 | + } |
| 147 | + Write-Verbose 'Logging in using a managed installation access token...' |
| 148 | + $contextParams | Format-Table | Out-String -Stream | ForEach-Object { Write-Verbose $_ } |
| 149 | + $contextObj = [GitHubAppInstallationContext]::new((Set-GitHubContext -Context $contextParams.Clone() -PassThru -Default:$Default)) |
| 150 | + $contextObj | Format-List | Out-String -Stream | ForEach-Object { Write-Verbose $_ } |
| 151 | + if (-not $Silent) { |
| 152 | + $name = $contextObj.Name |
| 153 | + if ($script:IsGitHubActions) { |
| 154 | + $green = $PSStyle.Foreground.Green |
| 155 | + $reset = $PSStyle.Reset |
| 156 | + Write-Host "$green✓$reset Connected $name!" |
| 157 | + } else { |
| 158 | + Write-Host '✓ ' -ForegroundColor Green -NoNewline |
| 159 | + Write-Host "Connected $name!" |
| 160 | + } |
| 161 | + } |
| 162 | + if ($PassThru) { |
| 163 | + Write-Debug "Passing context [$contextObj] to the pipeline." |
| 164 | + Write-Output $contextObj |
| 165 | + } |
| 166 | + return |
| 167 | + } |
| 168 | + |
| 169 | + $Installation | ForEach-Object -ThrottleLimit $ThrottleLimit -Parallel { |
| 170 | + $params = @{ |
| 171 | + ID = $_.ID |
| 172 | + Context = $using:Context |
| 173 | + PassThru = $using:PassThru |
| 174 | + Silent = $using:Silent |
| 175 | + Default = $using:Default |
| 176 | + } |
| 177 | + Connect-GitHubApp @params |
| 178 | + } |
| 179 | + return |
| 180 | + } |
92 | 181 | 'Filtered' { |
| 182 | + $installations = Get-GitHubAppInstallation -Context $Context |
| 183 | + Write-Verbose "Found [$($installations.Count)] installations." |
| 184 | + |
93 | 185 | $User | ForEach-Object { |
94 | 186 | $userItem = $_ |
95 | 187 | Write-Verbose "User filter: [$userItem]." |
|
111 | 203 | $_.Type -eq 'Enterprise' -and $_.Target.Name -like $enterpriseItem |
112 | 204 | } |
113 | 205 | } |
114 | | - } |
115 | | - default { |
116 | | - Write-Verbose 'No target specified. Connecting to all installations.' |
117 | | - $selectedInstallations = $installations |
118 | | - } |
119 | | - } |
120 | | - |
121 | | - Write-Verbose "Found [$($selectedInstallations.Count)] installations for the target." |
122 | | - $selectedInstallations | ForEach-Object { |
123 | | - $installation = $_ |
124 | | - Write-Verbose "Processing installation [$($installation.Target.Name)] [$($installation.id)]" |
125 | | - $token = New-GitHubAppInstallationAccessToken -Context $Context -ID $installation.id |
126 | | - |
127 | | - $contextParams = @{ |
128 | | - AuthType = [string]'IAT' |
129 | | - TokenType = [string]'ghs' |
130 | | - DisplayName = [string]$Context.DisplayName |
131 | | - ApiBaseUri = [string]$Context.ApiBaseUri |
132 | | - ApiVersion = [string]$Context.ApiVersion |
133 | | - HostName = [string]$Context.HostName |
134 | | - HttpVersion = [string]$Context.HttpVersion |
135 | | - PerPage = [int]$Context.PerPage |
136 | | - ClientID = [string]$Context.ClientID |
137 | | - InstallationID = [string]$installation.ID |
138 | | - Permissions = [GitHubPermission[]]$installation.Permissions |
139 | | - Events = [string[]]$installation.Events |
140 | | - InstallationType = [string]$installation.Type |
141 | | - Token = [securestring]$token.Token |
142 | | - TokenExpiresAt = [datetime]$token.ExpiresAt |
143 | | - } |
144 | | - |
145 | | - switch ($installation.Type) { |
146 | | - 'User' { |
147 | | - $contextParams['InstallationName'] = [string]$installation.Target.Name |
148 | | - $contextParams['Owner'] = [string]$installation.Target.Name |
149 | | - } |
150 | | - 'Organization' { |
151 | | - $contextParams['InstallationName'] = [string]$installation.Target.Name |
152 | | - $contextParams['Owner'] = [string]$installation.Target.Name |
153 | | - } |
154 | | - 'Enterprise' { |
155 | | - $contextParams['InstallationName'] = [string]$installation.Target.Name |
156 | | - $contextParams['Enterprise'] = [string]$installation.Target.Name |
| 206 | + $selectedInstallations | ForEach-Object -ThrottleLimit $ThrottleLimit -Parallel { |
| 207 | + $params = @{ |
| 208 | + ID = $_.ID |
| 209 | + Context = $using:Context |
| 210 | + PassThru = $using:PassThru |
| 211 | + Silent = $using:Silent |
| 212 | + Default = $using:Default |
| 213 | + } |
| 214 | + Connect-GitHubApp @params |
157 | 215 | } |
| 216 | + return |
158 | 217 | } |
159 | | - Write-Verbose 'Logging in using a managed installation access token...' |
160 | | - $contextParams | Format-Table | Out-String -Stream | ForEach-Object { Write-Verbose $_ } |
161 | | - $contextObj = [GitHubAppInstallationContext]::new((Set-GitHubContext -Context $contextParams.Clone() -PassThru -Default:$Default)) |
162 | | - $contextObj | Format-List | Out-String -Stream | ForEach-Object { Write-Verbose $_ } |
163 | | - if (-not $Silent) { |
164 | | - $name = $contextObj.Name |
165 | | - if ($script:IsGitHubActions) { |
166 | | - $green = $PSStyle.Foreground.Green |
167 | | - $reset = $PSStyle.Reset |
168 | | - Write-Host "$green✓$reset Connected $name!" |
169 | | - } else { |
170 | | - Write-Host '✓ ' -ForegroundColor Green -NoNewline |
171 | | - Write-Host "Connected $name!" |
| 218 | + 'All Installations' { |
| 219 | + Write-Verbose 'No target specified. Connecting to all installations.' |
| 220 | + $selectedInstallations = Get-GitHubAppInstallation -Context $Context |
| 221 | + $selectedInstallations | ForEach-Object -ThrottleLimit $ThrottleLimit -Parallel { |
| 222 | + $params = @{ |
| 223 | + ID = $_.ID |
| 224 | + Context = $using:Context |
| 225 | + PassThru = $using:PassThru |
| 226 | + Silent = $using:Silent |
| 227 | + Default = $using:Default |
| 228 | + } |
| 229 | + Connect-GitHubApp @params |
172 | 230 | } |
| 231 | + return |
173 | 232 | } |
174 | | - if ($PassThru) { |
175 | | - Write-Debug "Passing context [$contextObj] to the pipeline." |
176 | | - Write-Output $contextObj |
177 | | - } |
178 | | - $contextParams.Clear() |
179 | 233 | } |
180 | | - |
181 | 234 | } |
182 | 235 |
|
183 | 236 | end { |
|
0 commit comments