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. .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 $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 ) 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 { $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: $($headers | ConvertTo-Json -Compress)" 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 $_ } } } |