Files
Tanium/API/Deploy - Create.ps1
2025-10-31 08:59:02 +01:00

197 lines
7.3 KiB
PowerShell
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<#
.SYNOPSIS
Create a Tanium Deploy software package using the Deploy module cmdlets.
Strategy: clone an existing package to get the exact schema, then modify a few fields.
REQUIRES: Redden-TanREST (for the Deploy cmdlets your screenshot shows)
#>
# =============== Block 0 - Parameters to edit ===============
# New package name and install command
$NewPackageName = 'Demo - My Package (API)'
$InstallCommandLine = 'cmd /c echo Hello from Deploy > %TEMP%\hello.txt'
# Choose ONE mode: 'CommandOnly' | 'LocalFile' | 'RemoteURL'
$Mode = 'CommandOnly'
# If Mode = LocalFile
$LocalFilePath = 'C:\Temp\payload.msi'
# If Mode = RemoteURL
$RemoteFileUrl = 'https://example.com/payload.msi'
# An existing simple package to use as a schema template (must exist in your Deploy)
$TemplatePackageName = 'Notepad++ (Gallery)' # <-- mets ici un paquet simple qui existe chez toi
# Optional: content set ID (leave as-is to keep the template's)
$OverrideContentSetId = $null # ex: 0 (ou $null pour garder lID du template)
# =============== Block 1 - Import & Session ===============
$ErrorActionPreference = 'Stop'
Import-Module Redden-TanREST -Force
# Load config.json next to this script
$configPath = Join-Path $PSScriptRoot 'config.json'
if (-not (Test-Path $configPath)) { throw "Configuration file not found: $configPath" }
$config = Get-Content -Path $configPath -Raw | ConvertFrom-Json
$TaniumUrl = $config.TaniumUrl
$TaniumToken = $config.TaniumApiToken
if ([string]::IsNullOrWhiteSpace($TaniumUrl) -or [string]::IsNullOrWhiteSpace($TaniumToken)) {
throw "Both TaniumUrl and TaniumApiToken must be provided in config.json."
}
if ($TaniumUrl -match '^https?://') { $TaniumUrl = $TaniumUrl -replace '^https?://','' -replace '/+$','' }
# Create a short-lived CLIXML for Initialize-TaniumSession (same pattern as your other scripts)
$TempXml = Join-Path $env:TEMP 'tanium-session-tmp.apicred'
$ExportObject = @{
baseURI = $TaniumUrl
token = ($TaniumToken | ConvertTo-SecureString -AsPlainText -Force)
}
$ExportObject | Export-Clixml -Path $TempXml
Initialize-TaniumSession -PathToXML $TempXml
Write-Host "Tanium session initialized."
# =============== Block 2 - Helpers ===============
function DeepClone($obj) {
# round-trip through JSON for a deep copy
return ($obj | ConvertTo-Json -Depth 100 | ConvertFrom-Json)
}
function Remove-ReadOnlyProps {
param([Parameter(Mandatory)]$o)
# remove common read-only or server-managed fields wherever they appear
$remove = @('id','createdAt','createdBy','updatedAt','updatedBy','lastModified','created','modified','revision','status')
if ($o -is [System.Collections.IDictionary]) {
foreach ($k in @($o.Keys)) {
if ($remove -contains [string]$k) { $o.Remove($k) | Out-Null; continue }
$o[$k] = Remove-ReadOnlyProps $o[$k]
}
return $o
} elseif ($o -is [System.Collections.IEnumerable] -and -not ($o -is [string])) {
$new = @()
foreach ($item in $o) { $new += ,(Remove-ReadOnlyProps $item) }
return $new
} else {
return $o
}
}
function Replace-AllTempFileIds {
param(
[Parameter(Mandatory)]$o,
[Parameter(Mandatory)][string]$NewTempFileId
)
# replace any property named 'tempFileId' or 'fileId' with the new tempfile id (common API shapes)
$matchKeys = @('tempFileId','fileId')
if ($o -is [System.Collections.IDictionary]) {
foreach ($k in @($o.Keys)) {
if ($matchKeys -contains [string]$k) {
$o[$k] = $NewTempFileId
} else {
$o[$k] = Replace-AllTempFileIds -o $o[$k] -NewTempFileId $NewTempFileId
}
}
return $o
} elseif ($o -is [System.Collections.IEnumerable] -and -not ($o -is [string])) {
$new = @()
foreach ($item in $o) { $new += ,(Replace-AllTempFileIds -o $item -NewTempFileId $NewTempFileId) }
return $new
} else {
return $o
}
}
function Update-InstallCommand {
param(
[Parameter(Mandatory)]$o,
[Parameter(Mandatory)][string]$CommandLine
)
# best-effort: update common command fields if found
$cmdKeys = @('command','commandLine','installCommand','install_command','command_line')
if ($o -is [System.Collections.IDictionary]) {
foreach ($k in @($o.Keys)) {
if ($cmdKeys -contains [string]$k -and ($o[$k] -is [string])) {
$o[$k] = $CommandLine
} else {
$o[$k] = Update-InstallCommand -o $o[$k] -CommandLine $CommandLine
}
}
return $o
} elseif ($o -is [System.Collections.IEnumerable] -and -not ($o -is [string])) {
$new = @()
foreach ($item in $o) { $new += ,(Update-InstallCommand -o $item -CommandLine $CommandLine) }
return $new
} else {
return $o
}
}
# =============== Block 3 - Fetch template & prepare body ===============
Write-Host "Fetching template package: $TemplatePackageName"
$template = Get-DeploySoftwarePackage -Name $TemplatePackageName -IncludeHidden
if (-not $template) { throw "Template package '$TemplatePackageName' not found." }
# If multiple, take the first
if ($template -is [System.Array]) { $template = $template[0] }
# Deep clone and strip read-only fields
$bodyObj = DeepClone $template
$bodyObj = Remove-ReadOnlyProps $bodyObj
# Apply basic changes
$bodyObj.name = $NewPackageName
if ($OverrideContentSetId -ne $null) {
if ($bodyObj.contentSet -and $bodyObj.contentSet.id -ne $null) {
$bodyObj.contentSet.id = [int]$OverrideContentSetId
}
}
# Update command line everywhere it appears (best-effort)
$bodyObj = Update-InstallCommand -o $bodyObj -CommandLine $InstallCommandLine
# =============== Block 4 - Attach file if requested ===============
$tempFile = $null
switch ($Mode) {
'LocalFile' {
Write-Host "Uploading local file: $LocalFilePath"
if (-not (Test-Path $LocalFilePath)) { throw "Local file not found: $LocalFilePath" }
$tempFile = New-DeployTempFile -FilePath $LocalFilePath
if (-not $tempFile) { throw "Failed to upload local file." }
$bodyObj = Replace-AllTempFileIds -o $bodyObj -NewTempFileId ([string]$tempFile.id)
}
'RemoteURL' {
Write-Host "Registering remote file URL: $RemoteFileUrl"
$tempFile = New-DeployTempFile -RemoteURL $RemoteFileUrl
if (-not $tempFile) { throw "Failed to register remote URL." }
$bodyObj = Replace-AllTempFileIds -o $bodyObj -NewTempFileId ([string]$tempFile.id)
}
'CommandOnly' {
Write-Host "No file attachment (command-only mode)."
}
default { throw "Unknown Mode '$Mode' (use CommandOnly | LocalFile | RemoteURL)" }
}
# =============== Block 5 - Create software package ===============
# Convert to JSON for -Body
$bodyJson = $bodyObj | ConvertTo-Json -Depth 100
Write-Host "Creating Deploy software package: $NewPackageName"
$newPkg = New-DeploySoftwarePackage -Body ($bodyJson | ConvertFrom-Json)
# Certains modules attendent un objet PS, dautres une chaîne JSON ; si erreur, essaie directement -Body $bodyJson
if (-not $newPkg) {
Write-Warning "New-DeploySoftwarePackage returned no object. Verify in console if the package exists."
} else {
Write-Host "Created: ID=$($newPkg.id) Name=$($newPkg.name)"
}
# Optional: verify by name
$check = Get-DeploySoftwarePackage -Name $NewPackageName -IncludeHidden
if ($check) {
Write-Host "Verified package exists. Done."
} else {
Write-Warning "Package not found via Get-DeploySoftwarePackage; please check the console or API logs."
}
# Cleanup temp clixml (optional)
Remove-Item -Path $TempXml -Force -ErrorAction SilentlyContinue