Public/Authentication/Connect-FleetDM.ps1
|
function Connect-FleetDM { <# .SYNOPSIS Establishes a connection to the FleetDM API .DESCRIPTION Connects to a FleetDM instance using either an API token or email/password credentials. The connection is stored at the module level and used by all other FleetDM cmdlets. .PARAMETER BaseUri The base URI of your FleetDM instance (e.g., https://fleet.example.com) .PARAMETER ApiToken A secure string containing the FleetDM API token. This is the preferred method for automation and API-only users. .PARAMETER Credential PSCredential object containing email and password for FleetDM authentication. Use this for interactive sessions or when token authentication is not available. .PARAMETER Email Fleet user email. Same value as fleetctl login --email. .PARAMETER Password Fleet user password. Same value as fleetctl login --password. .EXAMPLE $token = ConvertTo-SecureString "your-api-token" -AsPlainText -Force Connect-FleetDM -BaseUri "https://fleet.example.com" -ApiToken $token Connects to FleetDM using an API token .EXAMPLE $password = Read-Host "Password" -AsSecureString Connect-FleetDM -BaseUri "https://fleet.example.com" -Email "admin@example.com" -Password $password Logs in with email and password, the same call as fleetctl login --email --password .EXAMPLE $cred = Get-Credential Connect-FleetDM -BaseUri "https://fleet.example.com" -Credential $cred Prompts for credentials and connects to FleetDM .EXAMPLE Connect-FleetDM -BaseUri "https://fleet.example.com" -ApiToken (Read-Host -AsSecureString "Enter API Token") Prompts for API token securely and connects to FleetDM .LINK https://fleetdm.com/docs/using-fleet/rest-api#authentication #> [CmdletBinding(DefaultParameterSetName = 'Token')] param( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [ValidatePattern('^https?://')] [string]$BaseUri, [Parameter(Mandatory, ParameterSetName = 'Token')] [securestring]$ApiToken, [Parameter(Mandatory, ParameterSetName = 'Credential')] [pscredential]$Credential, [Parameter(Mandatory, ParameterSetName = 'Email')] [ValidateNotNullOrEmpty()] [string]$Email, [Parameter(Mandatory, ParameterSetName = 'Email')] [securestring]$Password ) begin { # Remove trailing slash from BaseUri if present $BaseUri = $BaseUri.TrimEnd('/') # Initialize web session for connection pooling $script:FleetDMWebSession = New-Object Microsoft.PowerShell.Commands.WebRequestSession } process { try { if ($PSCmdlet.ParameterSetName -eq 'Email') { $Credential = [pscredential]::new($Email, $Password) } $headers = @{ 'Content-Type' = 'application/json' } if ($PSCmdlet.ParameterSetName -eq 'Token') { # Convert secure string to plain text - use PtrToStringBSTR for cross-platform compatibility $tokenBstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($ApiToken) $tokenPlain = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($tokenBstr) # Clean up the BSTR [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($tokenBstr) $headers['Authorization'] = "Bearer $tokenPlain" Write-Verbose "Attempting token-based authentication to $BaseUri" } else { # Login with credentials Write-Verbose "Attempting credential-based authentication to $BaseUri" $loginBody = @{ email = $Credential.UserName password = $Credential.GetNetworkCredential().Password } | ConvertTo-Json $loginUri = "$BaseUri/api/v1/fleet/login" try { $loginResponse = Invoke-RestMethod -Uri $loginUri ` -Method POST ` -Body $loginBody ` -ContentType 'application/json' ` -WebSession $script:FleetDMWebSession ` -ErrorAction Stop if (-not $loginResponse.token) { throw "No token received from FleetDM login endpoint" } $headers['Authorization'] = "Bearer $($loginResponse.token)" Write-Verbose "Successfully authenticated as $($loginResponse.user.email)" } catch { throw "Failed to authenticate with FleetDM: $($_.Exception.Message)" } } # Test connection by getting version $versionUri = "$BaseUri/api/v1/fleet/version" Write-Verbose "Testing connection to: $versionUri" Write-Verbose "Headers: $(Get-FleetRedactedLogText -Text $headers)" try { $webResponse = Invoke-WebRequest -Uri $versionUri ` -Headers $headers ` -WebSession $script:FleetDMWebSession ` -ErrorAction Stop # Parse response based on content type if ($webResponse.Headers['Content-Type'] -like 'application/json*') { $versionResponse = $webResponse.Content | ConvertFrom-Json } else { # Try to parse as JSON anyway try { $versionResponse = $webResponse.Content | ConvertFrom-Json } catch { throw "Unexpected response format from version endpoint" } } Write-Verbose "Successfully connected to FleetDM version $($versionResponse.version)" } catch { Write-Verbose "Error details: $($_.Exception.Message)" Write-Verbose "Error type: $($_.Exception.GetType().FullName)" if ($_.Exception.Response -and $_.Exception.Response.StatusCode -eq 'Unauthorized') { throw "Authentication failed. Please check your credentials or API token." } else { throw "Failed to connect to FleetDM: $($_.Exception.Message)" } } # Get current user information $meUri = "$BaseUri/api/v1/fleet/me" try { $userInfo = Invoke-RestMethod -Uri $meUri ` -Headers $headers ` -WebSession $script:FleetDMWebSession ` -ErrorAction Stop Write-Verbose "Authenticated as: $($userInfo.user.name) ($($userInfo.user.email))" Write-Verbose "Global role: $($userInfo.user.global_role)" } catch { Write-Warning "Could not retrieve user information" $userInfo = $null } # Store connection information $script:FleetDMConnection = @{ BaseUri = $BaseUri Headers = $headers Version = $versionResponse.version User = $userInfo.user ConnectedAt = Get-Date } # Create output object $connectionInfo = [PSCustomObject]@{ PSTypeName = 'FleetDM.Connection' BaseUri = $BaseUri Version = $versionResponse.version User = if ($userInfo) { $userInfo.user.email } else { 'Unknown' } GlobalRole = if ($userInfo) { $userInfo.user.global_role } else { 'Unknown' } ConnectedAt = $script:FleetDMConnection.ConnectedAt } Write-Host "Successfully connected to FleetDM at $BaseUri" -ForegroundColor Green Write-Host "Version: $($versionResponse.version)" -ForegroundColor Cyan if ($userInfo) { Write-Host "Authenticated as: $($userInfo.user.email) [$($userInfo.user.global_role)]" -ForegroundColor Cyan } return $connectionInfo } catch { # Clear any partial connection data $script:FleetDMConnection = $null $script:FleetDMWebSession = $null throw $_ } } } |