209 lines
7.9 KiB
PowerShell
209 lines
7.9 KiB
PowerShell
<#
|
|
.SYNOPSIS
|
|
Create Tanium action packages from a definition array supporting three modes:
|
|
- CommandOnly : only a command (no files)
|
|
- Upload : upload local files into the package, then execute from .\__Download\
|
|
- Url : reference a remote file by URL with SHA-256 and "check for update" TTL
|
|
|
|
The script:
|
|
1) Initializes a Tanium session from config.json (same folder as the script),
|
|
2) Iterates over $packages and creates each package accordingly,
|
|
3) Optionally uploads payloads (Upload mode), or references URL files (Url mode),
|
|
4) Cleans up the temporary CLIXML.
|
|
|
|
NOTES
|
|
- Keep config.json out of version control.
|
|
- When executing an uploaded file, always reference it via .\__Download\<file> in -Command.
|
|
#>
|
|
|
|
# =========================
|
|
# Block 1 - Prerequisites
|
|
# =========================
|
|
$ErrorActionPreference = 'Stop'
|
|
try { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 } catch {}
|
|
Import-Module Redden-TanREST -Force
|
|
|
|
# =========================
|
|
# Block 2 - Load config.json & init session
|
|
# =========================
|
|
$configPath = Join-Path $PSScriptRoot 'config.json'
|
|
$TempXml = Join-Path $env:TEMP 'tanium-session-tmp.apicred'
|
|
|
|
try {
|
|
if (-not (Test-Path $configPath)) { throw "Configuration file not found: $configPath" }
|
|
|
|
Write-Host "Reading configuration from: $configPath"
|
|
$config = Get-Content -Path $configPath -Raw | ConvertFrom-Json
|
|
|
|
$TaniumUrl = $config.TaniumUrl
|
|
$TaniumApiToken = $config.TaniumApiToken
|
|
if ([string]::IsNullOrWhiteSpace($TaniumUrl)) { $TaniumUrl = $env:TANIUM_URL }
|
|
if ([string]::IsNullOrWhiteSpace($TaniumApiToken)) { $TaniumApiToken = $env:TANIUM_TOKEN }
|
|
if ([string]::IsNullOrWhiteSpace($TaniumUrl) -or [string]::IsNullOrWhiteSpace($TaniumApiToken)) {
|
|
throw "Both TaniumUrl and TaniumApiToken must be provided (config.json or environment variables)."
|
|
}
|
|
|
|
# Normalize: bare host (no scheme / trailing slash)
|
|
if ($TaniumUrl -match '^https?://') {
|
|
$TaniumUrl = $TaniumUrl -replace '^https?://', '' -replace '/+$', ''
|
|
Write-Host "Normalized TaniumUrl to host: $TaniumUrl"
|
|
}
|
|
|
|
# Build temporary CLIXML for Initialize-TaniumSession
|
|
$ExportObject = @{
|
|
baseURI = $TaniumUrl
|
|
token = ($TaniumApiToken | ConvertTo-SecureString -AsPlainText -Force)
|
|
}
|
|
Write-Host "Writing temporary CLIXML to: $TempXml"
|
|
$ExportObject | Export-Clixml -Path $TempXml
|
|
|
|
Write-Host "Initializing Tanium session..."
|
|
Initialize-TaniumSession -PathToXML $TempXml
|
|
Write-Host "Tanium session initialized successfully."
|
|
}
|
|
catch {
|
|
Write-Error "Failed to initialize Tanium session. Details: $($_.Exception.Message)"
|
|
throw
|
|
}
|
|
|
|
# =========================
|
|
# Block 3 - Global settings
|
|
# =========================
|
|
$commandTimeout = 600 # seconds for New-TaniumPackage -Command_Timeout (default is 60)
|
|
$packageTTL = 3600 # seconds for New-TaniumPackage -Expire_Seconds (default is 660)
|
|
|
|
# Helper: optional SHA-256 calculator for a remote URL (only used if you don't supply it)
|
|
function Get-RemoteFileSha256 {
|
|
param([Parameter(Mandatory)][string]$Url)
|
|
$tmp = Join-Path $env:TEMP ([IO.Path]::GetRandomFileName())
|
|
try {
|
|
Invoke-WebRequest -Uri $Url -OutFile $tmp
|
|
(Get-FileHash -Algorithm SHA256 -Path $tmp).Hash.ToLowerInvariant()
|
|
} finally {
|
|
Remove-Item $tmp -Force -ErrorAction SilentlyContinue
|
|
}
|
|
}
|
|
|
|
# =========================
|
|
# Block 4 - Packages to create (3 cases)
|
|
# =========================
|
|
$packages = @(
|
|
# 1) Command only (no files)
|
|
@{
|
|
Name = 'Case1 - Command only'
|
|
Command = 'cmd /c ipconfig /all > %TEMP%\net.txt'
|
|
Mode = 'CommandOnly'
|
|
ContentSetID = 0
|
|
},
|
|
|
|
# 2) Upload local files (put files in UploadFolder; reference via .\__Download\ in Command)
|
|
@{
|
|
Name = 'Case2 - Upload a file'
|
|
Command = 'cmd /c cscript.exe .\__Download\cleanup.vbs'
|
|
Mode = 'Upload'
|
|
UploadFolder = 'C:\temp\pkg-cleanup' # must contain cleanup.vbs (and any other needed files)
|
|
ContentSetID = 2
|
|
},
|
|
|
|
# 3) URL file with "check for update" TTL (+ required SHA-256)
|
|
@{
|
|
Name = 'Case3 - URL file with update check'
|
|
Command = 'cmd /c cscript.exe .\__Download\remove-sample-files.vbs'
|
|
Mode = 'Url'
|
|
UrlFile = @{
|
|
Url = 'https://example.com/remove-sample-files.vbs'
|
|
Name = 'remove-sample-files.vbs'
|
|
Sha256 = '' # if empty, the script will compute it
|
|
CheckForUpdateSeconds = 86400 # e.g. 1 day; 0 = Never
|
|
}
|
|
ContentSetID = 2
|
|
}
|
|
)
|
|
|
|
# =========================
|
|
# Block 5 - Creation loop
|
|
# =========================
|
|
foreach ($pkg in $packages) {
|
|
Write-Host "`n=== Package: $($pkg.Name) ==="
|
|
|
|
try {
|
|
switch ($pkg.Mode) {
|
|
|
|
'CommandOnly' {
|
|
$newPkg = New-TaniumPackage `
|
|
-Name $pkg.Name `
|
|
-Command $pkg.Command `
|
|
-Expire_Seconds $packageTTL `
|
|
-Command_Timeout $commandTimeout `
|
|
-ContentSetID $pkg.ContentSetID
|
|
|
|
Write-Host "Created (ID=$($newPkg.id))"
|
|
}
|
|
|
|
'Upload' {
|
|
if (-not (Test-Path $pkg.UploadFolder)) {
|
|
throw "Upload folder not found: $($pkg.UploadFolder)"
|
|
}
|
|
|
|
$newPkg = New-TaniumPackage `
|
|
-Name $pkg.Name `
|
|
-Command $pkg.Command `
|
|
-Expire_Seconds $packageTTL `
|
|
-Command_Timeout $commandTimeout `
|
|
-ContentSetID $pkg.ContentSetID
|
|
|
|
Write-Host "Created (ID=$($newPkg.id)); uploading payload..."
|
|
Update-ActionPackageFile -PackageID $newPkg.id -UploadFolder $pkg.UploadFolder
|
|
Write-Host "Payload uploaded."
|
|
}
|
|
|
|
'Url' {
|
|
# Build Files[] entry expected by the API
|
|
$sha = $pkg.UrlFile.Sha256
|
|
if ([string]::IsNullOrWhiteSpace($sha)) {
|
|
Write-Host "Computing SHA-256 for URL: $($pkg.UrlFile.Url)"
|
|
$sha = Get-RemoteFileSha256 -Url $pkg.UrlFile.Url
|
|
}
|
|
|
|
$fileObj = [pscustomobject]@{
|
|
name = $pkg.UrlFile.Name
|
|
url = $pkg.UrlFile.Url
|
|
hash = $sha
|
|
# The property below controls "Check for update" TTL in seconds.
|
|
# If your Tanium uses a different name (e.g. cache_ttl_seconds/refresh_seconds), adjust here:
|
|
check_for_update_seconds = $pkg.UrlFile.CheckForUpdateSeconds
|
|
}
|
|
|
|
$newPkg = New-TaniumPackage `
|
|
-Name $pkg.Name `
|
|
-Command $pkg.Command `
|
|
-Expire_Seconds $packageTTL `
|
|
-Command_Timeout $commandTimeout `
|
|
-ContentSetID $pkg.ContentSetID `
|
|
-Files @($fileObj)
|
|
|
|
Write-Host "Created (ID=$($newPkg.id)) with remote file URL."
|
|
}
|
|
|
|
default {
|
|
throw "Unknown Mode for package '$($pkg.Name)'. Use 'CommandOnly' | 'Upload' | 'Url'."
|
|
}
|
|
}
|
|
}
|
|
catch {
|
|
Write-Error "Failed to process package '$($pkg.Name)': $($_.Exception.Message)"
|
|
}
|
|
}
|
|
|
|
# =========================
|
|
# Block 6 - Cleanup
|
|
# =========================
|
|
try {
|
|
if (Test-Path $TempXml) {
|
|
Remove-Item $TempXml -Force -ErrorAction SilentlyContinue
|
|
Write-Host "Temporary CLIXML removed: $TempXml"
|
|
}
|
|
} catch {
|
|
Write-Warning "Could not remove temporary CLIXML ($TempXml): $($_.Exception.Message)"
|
|
}
|