Auto-commit: 2025-10-31 08:59:02
This commit is contained in:
196
API/Deploy - Create.ps1
Normal file
196
API/Deploy - Create.ps1
Normal file
@@ -0,0 +1,196 @@
|
||||
<#
|
||||
.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 l’ID 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, d’autres 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
|
||||
Reference in New Issue
Block a user