Auto-commit: 2025-10-31 08:59:02
This commit is contained in:
264
API/RBAC_ImportRole_Redden-TanREST KO.ps1
Normal file
264
API/RBAC_ImportRole_Redden-TanREST KO.ps1
Normal file
@@ -0,0 +1,264 @@
|
||||
#requires -Version 7.0
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Ensure a Tanium role by NAME: update if it exists, else create, then update from JSON.
|
||||
|
||||
.DESCRIPTION
|
||||
- Accepts two JSON shapes:
|
||||
(A) Custom: { "Description": "...", "Permissions": { "<Content Set>": { "privileges": { "#x":[ "...", ... ] } } }, "Display Name": "..." }
|
||||
(B) Tanium export: { "object_list": { "content_set_roles": [ { name, description, content_set_role_privileges: [...] } ] } }
|
||||
- Forces role name to -RoleName.
|
||||
- Creates role if missing, then calls Update-TaniumRole.
|
||||
|
||||
.PARAMETER RoleName
|
||||
Target role name to ensure (forced into JSON before update).
|
||||
|
||||
.PARAMETER PathToRoleJSON
|
||||
Path to the role JSON file (custom or Tanium export).
|
||||
|
||||
.PARAMETER ContentSetOverride
|
||||
Optional content set ID to force in Update-TaniumRole.
|
||||
|
||||
.PARAMETER ConfigPath
|
||||
Path to config.json containing TaniumUrl and TaniumApiToken (default: alongside script).
|
||||
|
||||
.EXAMPLE
|
||||
.\Ensure-TaniumRole.ps1 -RoleName "test - T2_TANIUM - N2 - Patch Operator" -PathToRoleJSON .\test.json
|
||||
#>
|
||||
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $true, Position = 0)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]$RoleName,
|
||||
|
||||
[Parameter(Mandatory = $true, Position = 1)]
|
||||
[ValidateScript({
|
||||
if (-not (Test-Path $_ -PathType Leaf)) { throw "File not found: $_" }
|
||||
if ([IO.Path]::GetExtension($_) -notin '.json','.JSON') { throw "Not a .json file: $_" }
|
||||
$true
|
||||
})]
|
||||
[string]$PathToRoleJSON,
|
||||
|
||||
[Parameter(Position = 2)]
|
||||
[int]$ContentSetOverride = 0,
|
||||
|
||||
[string]$ConfigPath = (Join-Path $PSScriptRoot 'config.json')
|
||||
)
|
||||
|
||||
begin {
|
||||
$ErrorActionPreference = 'Stop'
|
||||
try { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 } catch {}
|
||||
|
||||
if (-not (Get-Command -Name Update-TaniumRole -ErrorAction SilentlyContinue)) {
|
||||
throw "Update-TaniumRole not found. Import the module that defines it before running this script."
|
||||
}
|
||||
|
||||
# Load input JSON (any shape)
|
||||
try {
|
||||
$inObj = Get-Content -Path $PathToRoleJSON -Raw | ConvertFrom-Json -ErrorAction Stop
|
||||
} catch {
|
||||
throw "Invalid JSON in '$PathToRoleJSON': $($_.Exception.Message)"
|
||||
}
|
||||
|
||||
function Convert-CustomRoleJsonToTaniumExport {
|
||||
<#
|
||||
Input (custom):
|
||||
{
|
||||
"Description": "...",
|
||||
"Permissions": {
|
||||
"ContentSetA": { "privileges": { "#patch": [ "patch X", "patch Y" ], "#admin":[ "read sensor" ] } },
|
||||
"ContentSetB": { ... }
|
||||
},
|
||||
"Display Name": "..."
|
||||
}
|
||||
Output (export):
|
||||
{
|
||||
"comment":"Generated for Update-TaniumRole",
|
||||
"version":2,
|
||||
"object_list":{
|
||||
"content_set_roles":[
|
||||
{
|
||||
"name":"<RoleName>",
|
||||
"description":"<Description>",
|
||||
"deny_flag":0,
|
||||
"all_content_sets_flag":0,
|
||||
"reserved_name":"",
|
||||
"category":"custom",
|
||||
"content_set_role_privileges":[
|
||||
{ "content_set":{"name":"ContentSetA"}, "content_set_privilege":{"name":"patch X"}, "json_metadata":"" },
|
||||
...
|
||||
],
|
||||
"metadata":[]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
#>
|
||||
param(
|
||||
[Parameter(Mandatory)][object]$InputObject,
|
||||
[Parameter(Mandatory)][string]$NameToForce
|
||||
)
|
||||
|
||||
$desc = ''
|
||||
if ($InputObject.'Description') { $desc = [string]$InputObject.'Description' }
|
||||
elseif ($InputObject.description) { $desc = [string]$InputObject.description }
|
||||
|
||||
$privRows = New-Object System.Collections.Generic.List[object]
|
||||
if ($InputObject.Permissions -is [object]) {
|
||||
foreach ($csName in $InputObject.Permissions.PSObject.Properties.Name) {
|
||||
$csBlock = $InputObject.Permissions.$csName
|
||||
if ($csBlock -and $csBlock.privileges) {
|
||||
foreach ($cat in $csBlock.privileges.PSObject.Properties.Name) {
|
||||
$vals = $csBlock.privileges.$cat
|
||||
if ($vals -is [System.Collections.IEnumerable]) {
|
||||
foreach ($p in $vals) {
|
||||
if ([string]::IsNullOrWhiteSpace($p)) { continue }
|
||||
$privRows.Add([pscustomobject]@{
|
||||
content_set = @{ name = $csName }
|
||||
content_set_privilege = @{ name = [string]$p }
|
||||
json_metadata = ""
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# De-duplicate
|
||||
$unique = $privRows |
|
||||
Group-Object { "$($_.content_set.name)|$($_.content_set_privilege.name)" } |
|
||||
ForEach-Object { $_.Group[0] }
|
||||
|
||||
return [pscustomobject]@{
|
||||
comment = "Generated for Update-TaniumRole"
|
||||
version = 2
|
||||
object_list = @{
|
||||
content_set_roles = @(
|
||||
[pscustomobject]@{
|
||||
name = $NameToForce
|
||||
description = $desc
|
||||
deny_flag = 0
|
||||
all_content_sets_flag = 0
|
||||
reserved_name = ""
|
||||
category = "custom"
|
||||
content_set_role_privileges = $unique
|
||||
metadata = @()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Normalize to Tanium export shape
|
||||
$exportObj = $null
|
||||
if ($inObj.object_list -and $inObj.object_list.content_set_roles) {
|
||||
# Already export shape
|
||||
$exportObj = $inObj
|
||||
# enforce RoleName on the single role (or first)
|
||||
$rolesArr = @($exportObj.object_list.content_set_roles)
|
||||
if ($rolesArr.Count -eq 0) { throw "Export JSON contains no roles." }
|
||||
if ($rolesArr.Count -gt 1) {
|
||||
# Force only the first for safety; or throw if you want strict single-role files
|
||||
throw "JSON contains multiple roles. Provide a single-role file or split it."
|
||||
}
|
||||
$exportObj.object_list.content_set_roles[0].name = $RoleName
|
||||
}
|
||||
else {
|
||||
# Custom shape -> convert
|
||||
if (-not $inObj.Permissions) {
|
||||
throw "No content_set_roles[] found AND no Permissions{} block found in JSON."
|
||||
}
|
||||
$exportObj = Convert-CustomRoleJsonToTaniumExport -InputObject $inObj -NameToForce $RoleName
|
||||
}
|
||||
|
||||
# Write temp JSON (don't touch original)
|
||||
$ts = Get-Date -Format 'yyyyMMdd-HHmmss'
|
||||
$tempJson = Join-Path $env:TEMP ("tanium-role-{0}-{1}.json" -f ($RoleName -replace '[^\w\-\. ]','_'), $ts)
|
||||
$exportObj | ConvertTo-Json -Depth 100 | Set-Content -Path $tempJson -Encoding utf8
|
||||
|
||||
# Tanium API bootstrap
|
||||
if (-not (Test-Path $ConfigPath -PathType Leaf)) {
|
||||
throw "Config file not found: $ConfigPath"
|
||||
}
|
||||
$cfg = Get-Content -Path $ConfigPath -Raw | ConvertFrom-Json
|
||||
$baseUrl = ($cfg.TaniumUrl -replace '/+$','')
|
||||
if ($baseUrl -notmatch '^https?://') { $baseUrl = "https://$baseUrl" }
|
||||
$headers = @{
|
||||
'Accept' = 'application/json'
|
||||
'Content-Type' = 'application/json'
|
||||
}
|
||||
if ($cfg.TaniumApiToken) {
|
||||
$headers['X-Api-Token'] = $cfg.TaniumApiToken
|
||||
$headers['session'] = $cfg.TaniumApiToken
|
||||
}
|
||||
|
||||
function Invoke-TaniumApi {
|
||||
param(
|
||||
[Parameter(Mandatory)][ValidateSet('GET','POST','PATCH','PUT','DELETE')] [string]$Method,
|
||||
[Parameter(Mandatory)][string]$Path,
|
||||
[object]$Body = $null
|
||||
)
|
||||
$uri = '{0}{1}' -f $baseUrl, $Path
|
||||
if ($Body -ne $null) {
|
||||
Invoke-RestMethod -Method $Method -Uri $uri -Headers $headers -Body ($Body | ConvertTo-Json -Depth 20) -ErrorAction Stop
|
||||
} else {
|
||||
Invoke-RestMethod -Method $Method -Uri $uri -Headers $headers -ErrorAction Stop
|
||||
}
|
||||
}
|
||||
|
||||
function Get-TaniumUserRolesAll {
|
||||
$resp = Invoke-TaniumApi -Method GET -Path '/api/v2/user_roles'
|
||||
if ($resp.items) { return @($resp.items) }
|
||||
if ($resp.data) { return @($resp.data) }
|
||||
if ($resp.user_roles) { return @($resp.user_roles) }
|
||||
if ($resp -is [System.Collections.IEnumerable]) { return @($resp) }
|
||||
return @()
|
||||
}
|
||||
|
||||
function Ensure-TaniumRoleIdByName {
|
||||
param([Parameter(Mandatory)][string]$Name,[string]$Description = '')
|
||||
$all = Get-TaniumUserRolesAll
|
||||
$existing = $all | Where-Object { $_.name -eq $Name } | Select-Object -First 1
|
||||
if ($existing -and $existing.id) { return [int]$existing.id }
|
||||
# create
|
||||
$body = @{
|
||||
name = $Name
|
||||
description = $Description
|
||||
category = 'custom'
|
||||
}
|
||||
$resp = Invoke-TaniumApi -Method POST -Path '/api/v2/user_roles' -Body $body
|
||||
if ($resp.id) { return [int]$resp.id }
|
||||
if ($resp.item -and $resp.item.id) { return [int]$resp.item.id }
|
||||
if ($resp.data -and $resp.data.id) { return [int]$resp.data.id }
|
||||
$all2 = Get-TaniumUserRolesAll
|
||||
$match = $all2 | Where-Object { $_.name -eq $Name } | Select-Object -First 1
|
||||
if ($match -and $match.id) { return [int]$match.id }
|
||||
throw "Role '$Name' created but ID could not be determined."
|
||||
}
|
||||
|
||||
# Description from export for creation metadata
|
||||
$desc = ''
|
||||
try { $desc = [string]$exportObj.object_list.content_set_roles[0].description } catch {}
|
||||
$script:TargetRoleId = Ensure-TaniumRoleIdByName -Name $RoleName -Description $desc
|
||||
}
|
||||
|
||||
process {
|
||||
try {
|
||||
$params = @{
|
||||
RoleIDs = @($script:TargetRoleId)
|
||||
PathToRoleJSON = $tempJson
|
||||
}
|
||||
if ($ContentSetOverride -gt 0) { $params['ContentSetOverride'] = $ContentSetOverride }
|
||||
|
||||
Write-Host "Ensured role '$RoleName' (ID: $($script:TargetRoleId)). Applying JSON..." -ForegroundColor Cyan
|
||||
$result = Update-TaniumRole @params
|
||||
$result
|
||||
}
|
||||
finally {
|
||||
if (Test-Path $tempJson) {
|
||||
Remove-Item -Path $tempJson -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user