Public/Connect-VMetric.ps1
|
function Connect-VMetric { <# .SYNOPSIS Signs in to VirtualMetric. .DESCRIPTION Connect-VMetric signs you in to a VirtualMetric console so the other VirtualMetric cmdlets can use its API. Give the console's address or the API's; they may be on different origins. The module asks the API for its metadata (GET /api/v1/cli/metadata), or reads the console's config.js, to find the other one, and validates both: https (plain http only to this machine), no user name, query or fragment. The browser goes to the console; every request goes to the API. By default it opens your browser: you sign in to the console as usual, pick the tenant, and approve the request; the browser then returns to PowerShell and you can close the tab. The module listens on 127.0.0.1 for that return and checks it with PKCE and a random state, so nothing else can finish the sign-in in your place. Cancel in the console stops the sign-in at once. Where no browser can be shown (Linux without a display, an SSH session) or with -UseDeviceAuthentication, it prints a code instead: open the address it gives on any device, enter the code, and approve. With -ApiToken it uses an API token as it is, for automation. The token's own tenant applies. The session is held in memory for this PowerShell session only. Signed-in sessions refresh themselves while you work and last up to 30 days; Disconnect-VMetric ends them. .PARAMETER Uri The console's address, such as https://console.example.com, or the API's, such as https://api.example.com/api/. A bare host name gets https://. .PARAMETER Tenant The tenant to use, by name or id. It is preselected in the console when you sign in; if you approve another one there, the module switches to this one afterwards (the session approved in the console is then replaced by the one for this tenant). If that switch fails, the approved session is kept but not made current, the current context stays as it was, and the error says how to use it. .PARAMETER UseDeviceAuthentication Sign in with a code entered on another device instead of the browser. .PARAMETER ApiToken An API token, as a SecureString: Get-Secret from Microsoft.PowerShell.SecretManagement, or Read-Host -AsSecureString. .PARAMETER SkipCertificateCheck Do not verify the server's TLS certificate. Only for a test server with a self-signed certificate: anyone between you and the server could read your tokens. .PARAMETER PassThru Write the new context (VirtualMetric.Context) to the pipeline. .EXAMPLE Connect-VMetric -Uri https://console.example.com Opens the browser to sign in. .EXAMPLE Connect-VMetric -Uri https://console.example.com -UseDeviceAuthentication Prints a code to enter at https://console.example.com/cli/device from any device. .EXAMPLE Connect-VMetric -Uri https://console.example.com -ApiToken (Get-Secret VMetricToken) Uses an API token kept in a SecretManagement vault. .EXAMPLE Connect-VMetric -Uri https://console.example.com -Tenant Contoso -PassThru Signs in and switches to the Contoso tenant (an MSSP's subtenant, for example), then shows the context. .OUTPUTS VirtualMetric.Context, with -PassThru. .LINK Get-VMetricContext .LINK Set-VMetricContext .LINK Disconnect-VMetric #> [CmdletBinding(DefaultParameterSetName = 'Browser')] [OutputType('VirtualMetric.Context')] param( [Parameter(Mandatory, Position = 0)] [ValidateNotNullOrEmpty()] [string] $Uri, [Parameter(ParameterSetName = 'Browser')] [Parameter(ParameterSetName = 'DeviceCode')] [ValidateNotNullOrEmpty()] [string] $Tenant, # In its own set, so it picks that set; not Mandatory, as the catalog holds a switch never is. [Parameter(ParameterSetName = 'DeviceCode')] [switch] $UseDeviceAuthentication, [Parameter(Mandatory, ParameterSetName = 'ApiToken')] [System.Security.SecureString] $ApiToken, [switch] $SkipCertificateCheck, [switch] $PassThru ) # Sign-in prompts and the result line are information messages, shown unless -InformationAction says # otherwise. if (-not $PSBoundParameters.ContainsKey('InformationAction')) { $InformationPreference = 'Continue' } try { if ($SkipCertificateCheck) { Write-Warning 'Certificate checks are off: the server''s identity is not verified, so anyone between you and it could read your tokens. Use this only with a test server.' } # The address given may be the console's or the API's; they may be apart. $endpoint = Resolve-VMetricEndpoint -Uri $Uri -SkipCertificateCheck:$SkipCertificateCheck $address = @{ ApiUrl = $endpoint.ApiUrl; ConsoleUrl = $endpoint.ConsoleUrl } if ($PSCmdlet.ParameterSetName -eq 'ApiToken') { $session = New-VMetricSession @address -AuthMethod ApiToken -ApiToken $ApiToken -SkipCertificateCheck:$SkipCertificateCheck Initialize-VMetricApiTokenSession -Session $session } else { $answer = $null $method = 'DeviceCode' if (-not $UseDeviceAuthentication) { if (Test-VMetricHeadless) { Write-Information 'No browser can be shown here; signing in with a device code.' } else { $answer = Invoke-VMetricBrowserSignIn @address -TenantHint $Tenant -SkipCertificateCheck:$SkipCertificateCheck if ($answer) { $method = 'Browser' } } } if (-not $answer) { $answer = Invoke-VMetricDeviceSignIn @address -TenantHint $Tenant -SkipCertificateCheck:$SkipCertificateCheck } $session = New-VMetricSession @address -AuthMethod $method -TokenResponse $answer -SkipCertificateCheck:$SkipCertificateCheck if ($Tenant -and -not (Test-VMetricSessionTenant -Session $session -Tenant $Tenant)) { $session = Switch-VMetricSignInTenant -Session $session -Tenant $Tenant } } # Signing in again to the same place replaces the session held for it; the replaced one is ended. Register-VMetricSession -Session $session $account = if ($session.AuthMethod -eq 'ApiToken') { 'an API token' } else { ConvertTo-VMetricSafeText -Text ([string]$session.Email) } $tenantText = if ($session.TenantName) { " in tenant '$(ConvertTo-VMetricSafeText -Text ([string]$session.TenantName))'" } else { '' } $apiText = '' if (([uri]$session.ApiUrl).GetLeftPart([System.UriPartial]::Authority) -ne $session.ConsoleUrl) { $apiText = " (API $($session.ApiUrl))" } Write-Information "Connected to $($session.ConsoleUrl)$apiText as $account$tenantText." if ($PassThru) { ConvertTo-VMetricContextObject -Session $session } } catch { if (Test-VMetricFlowControl -ErrorRecord $_) { throw } Write-VMetricCmdletError -Cmdlet $PSCmdlet -ErrorRecord $_ -Terminating } } |