Auto-commit: 2025-10-31 08:59:02
This commit is contained in:
208
API/Package - Create.ps1
Normal file
208
API/Package - Create.ps1
Normal file
@@ -0,0 +1,208 @@
|
||||
<#
|
||||
.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)"
|
||||
}
|
||||
Reference in New Issue
Block a user