public/New-OsQueryConfig.ps1
|
function New-OsQueryConfig { <# .SYNOPSIS Generates a scaffold osquery daemon configuration file. .DESCRIPTION Creates a JSON osquery.conf with sensible defaults including scheduled queries for system info, users, processes, networking, and installed packages. Optionally generates a companion osquery.flags file. Writing to system paths requires elevated privileges (root/Administrator). .PARAMETER OutputPath Full path to write osquery.conf. Defaults to the platform-appropriate system path. .PARAMETER LogPath Directory for osqueryd log output. Defaults to the platform log directory. .PARAMETER HostIdentifier How the host identifies itself in logs. Valid values: hostname, uuid, instance. Default: hostname. .PARAMETER ScheduleSplayPercent Percentage to randomize query timing to avoid thundering herd. Default: 10. .PARAMETER PackageManager Package table to include in the scheduled package query. Auto-detected if not specified. .PARAMETER GenerateFlagsFile If specified, also writes an osquery.flags companion file alongside the config. .PARAMETER Force Overwrite an existing config file without prompting. .EXAMPLE New-OsQueryConfig Writes a scaffold config to the platform default path. .EXAMPLE New-OsQueryConfig -OutputPath "/tmp/osquery.conf" -GenerateFlagsFile -Force Writes config and flags file to /tmp/ without elevation, overwriting if present. .EXAMPLE New-OsQueryConfig -HostIdentifier uuid -ScheduleSplayPercent 20 -PackageManager rpm Generates a config using UUID host identification and the rpm_packages table. #> [CmdletBinding(SupportsShouldProcess)] param ( [parameter(Mandatory=$false)][string]$OutputPath, [parameter(Mandatory=$false)][string]$LogPath, [parameter(Mandatory=$false)] [ValidateSet('hostname', 'uuid', 'instance')] [string]$HostIdentifier = 'hostname', [parameter(Mandatory=$false)] [ValidateRange(0, 100)] [int]$ScheduleSplayPercent = 10, [parameter(Mandatory=$false)] [ValidateSet('deb', 'rpm', 'chocolatey', 'homebrew')] [string]$PackageManager, [parameter(Mandatory=$false)][switch]$GenerateFlagsFile, [parameter(Mandatory=$false)][switch]$Force ) # Platform-specific default paths if ($IsWindows) { $defaultConfigDir = 'C:\Program Files\osquery' $defaultLogPath = 'C:\Program Files\osquery\log' $defaultDbDir = 'C:\Program Files\osquery' } elseif ($IsMacOS) { $defaultConfigDir = '/var/osquery' $defaultLogPath = '/var/log/osquery' $defaultDbDir = '/var/osquery' } else { $defaultConfigDir = '/etc/osquery' $defaultLogPath = '/var/log/osquery' $defaultDbDir = '/var/osquery' } if ([string]::IsNullOrEmpty($OutputPath)) { $OutputPath = Join-Path $defaultConfigDir 'osquery.conf' } if ([string]::IsNullOrEmpty($LogPath)) { $LogPath = $defaultLogPath } # Warn if writing to a system path without elevation $systemPrefixes = @('/etc/', '/var/', 'C:\Program Files\') $needsElevation = $systemPrefixes | Where-Object { $OutputPath.StartsWith($_) } if ($needsElevation -and -not (Test-ElevatedPrivilege)) { Write-Warning "Writing to '$OutputPath' typically requires elevated privileges. Run as root or Administrator if the write fails." } # Auto-detect package manager if ([string]::IsNullOrEmpty($PackageManager)) { $PackageManager = if ($IsWindows) { 'chocolatey' } elseif ($IsMacOS) { 'homebrew' } elseif (Test-Path '/usr/bin/rpm') { 'rpm' } else { 'deb' } } $packageTable = switch ($PackageManager) { 'deb' { 'deb_packages' } 'rpm' { 'rpm_packages' } 'chocolatey' { 'chocolatey_packages' } 'homebrew' { 'homebrew_packages' } } $config = [ordered]@{ options = [ordered]@{ host_identifier = $HostIdentifier schedule_splay_percent = $ScheduleSplayPercent logger_plugin = 'filesystem' logger_path = $LogPath log_result_events = $true log_snapshot_on_exit = $true worker_threads = 2 enable_monitor = $true disable_watchdog = $false watchdog_level = 0 events_expiry = 3600 verbose = $false } schedule = [ordered]@{ system_info = [ordered]@{ query = 'SELECT hostname, cpu_brand, physical_memory, hardware_model FROM system_info;' interval = 3600 description = 'System hardware summary' } os_version = [ordered]@{ query = 'SELECT name, version, build, platform FROM os_version;' interval = 3600 description = 'Operating system version' } users = [ordered]@{ query = 'SELECT uid, username, description, directory, shell FROM users;' interval = 300 description = 'Local user accounts' } logged_in_users = [ordered]@{ query = "SELECT user, type, tty, host, datetime(time, 'unixepoch') AS login_time FROM logged_in_users;" interval = 60 description = 'Currently logged-in users' } processes = [ordered]@{ query = 'SELECT pid, name, path, cmdline, uid FROM processes;' interval = 60 description = 'Running processes' } listening_ports = [ordered]@{ query = 'SELECT pid, port, protocol, family, address FROM listening_ports;' interval = 300 description = 'Network listening ports' } startup_items = [ordered]@{ query = 'SELECT name, path, args, type, status FROM startup_items;' interval = 3600 description = 'Startup items and persistence' } installed_packages = [ordered]@{ query = "SELECT name, version, arch FROM $packageTable;" interval = 3600 description = "Installed packages ($packageTable)" } } decorators = [ordered]@{ load = @( 'SELECT uuid AS host_uuid FROM system_info;' 'SELECT user AS username FROM logged_in_users ORDER BY time DESC LIMIT 1;' ) } packs = [ordered]@{} } # Ensure output directory exists $configDir = Split-Path $OutputPath -Parent if (-not (Test-Path $configDir)) { if ($PSCmdlet.ShouldProcess($configDir, 'Create directory')) { New-Item -ItemType Directory -Path $configDir -Force | Out-Null } } # Check for existing file if ((Test-Path $OutputPath) -and -not $Force.IsPresent) { Write-Error "Config already exists at '$OutputPath'. Use -Force to overwrite." return } $json = $config | ConvertTo-Json -Depth 10 if ($PSCmdlet.ShouldProcess($OutputPath, 'Write osquery.conf')) { Set-Content -Path $OutputPath -Value $json -Encoding UTF8 Write-Verbose "Config written: $OutputPath" } # Optional flags file $flagsPath = $null if ($GenerateFlagsFile.IsPresent) { $flagsPath = Join-Path $configDir 'osquery.flags' $flags = @( "--config_plugin=filesystem" "--config_path=$OutputPath" "--logger_plugin=filesystem" "--logger_path=$LogPath" "--pidfile=$(Join-Path $defaultDbDir 'osquery.pidfile')" "--database_path=$(Join-Path $defaultDbDir 'osquery.db')" "--disable_watchdog=false" ) if ($PSCmdlet.ShouldProcess($flagsPath, 'Write osquery.flags')) { Set-Content -Path $flagsPath -Value ($flags -join "`n") -Encoding UTF8 Write-Verbose "Flags file written: $flagsPath" } } [PSCustomObject]@{ ConfigPath = $OutputPath FlagsPath = $flagsPath LogPath = $LogPath PackageTable = $packageTable } } |