diff --git a/API/ComputerGroup - Get.ps1 b/API/ComputerGroup - Get.ps1 deleted file mode 100644 index d956101..0000000 --- a/API/ComputerGroup - Get.ps1 +++ /dev/null @@ -1,106 +0,0 @@ -<# -.SYNOPSIS -Initialize Tanium session from config.json (no env vars). Prefer -CredentialObject (hashtable). -Falls back to -BaseURI/-Token or -BaseURI/-ApiToken, then ephemeral CLIXML if needed. -#> - -$ErrorActionPreference = 'Stop' -try { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 } catch {} -Import-Module Redden-TanREST -Force - -# --- Load config.json --- -$configPath = Join-Path $PSScriptRoot 'config.json' -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) -or [string]::IsNullOrWhiteSpace($TaniumApiToken)) { - throw "Both TaniumUrl and TaniumApiToken must be provided in config.json." -} - -# Normalize to bare host (strip scheme and trailing slash) -$BaseUriHost = (($TaniumUrl -replace '^https?://','') -replace '/+$','') -$SecureToken = $TaniumApiToken | ConvertTo-SecureString -AsPlainText -Force - -# --- Initialize session (feature-detected) --- -Write-Host "Initializing Tanium session..." -$cmd = Get-Command Initialize-TaniumSession -ErrorAction Stop -$paramNames = $cmd.Parameters.Keys -$initialized = $false -$lastError = $null - -# 1) Preferred: -CredentialObject (expects a hashtable with ContainsKey) -if (-not $initialized -and ($paramNames -contains 'CredentialObject')) { - try { - $credHash = @{ - baseURI = $BaseUriHost - token = $SecureToken - } - Initialize-TaniumSession -CredentialObject $credHash - $initialized = $true - Write-Host "Session initialized via -CredentialObject (hashtable)." - } catch { $lastError = $_ } -} - -# 2) Fallback: -BaseURI/-Token (token may be SecureString or string depending on module) -if (-not $initialized -and ($paramNames -contains 'BaseURI') -and ($paramNames -contains 'Token')) { - try { - Initialize-TaniumSession -BaseURI $BaseUriHost -Token $SecureToken - $initialized = $true - Write-Host "Session initialized via -BaseURI/-Token (SecureString)." - } catch { - $lastError = $_ - try { - Initialize-TaniumSession -BaseURI $BaseUriHost -Token $TaniumApiToken - $initialized = $true - Write-Host "Session initialized via -BaseURI/-Token (plain string)." - } catch { $lastError = $_ } - } -} - -# 3) Fallback: -BaseURI/-ApiToken (some versions use ApiToken) -if (-not $initialized -and ($paramNames -contains 'BaseURI') -and ($paramNames -contains 'ApiToken')) { - try { - Initialize-TaniumSession -BaseURI $BaseUriHost -ApiToken $SecureToken - $initialized = $true - Write-Host "Session initialized via -BaseURI/-ApiToken (SecureString)." - } catch { - $lastError = $_ - try { - Initialize-TaniumSession -BaseURI $BaseUriHost -ApiToken $TaniumApiToken - $initialized = $true - Write-Host "Session initialized via -BaseURI/-ApiToken (plain string)." - } catch { $lastError = $_ } - } -} - -# 4) Last resort: ephemeral CLIXML (-PathToXML), then cleanup -if (-not $initialized -and ($paramNames -contains 'PathToXML')) { - try { - $TempXml = Join-Path $env:TEMP ('tanium-session-{0}.apicred' -f ([guid]::NewGuid())) - @{ baseURI = $BaseUriHost; token = $SecureToken } | Export-Clixml -Path $TempXml - Initialize-TaniumSession -PathToXML $TempXml - Remove-Item $TempXml -Force -ErrorAction SilentlyContinue - $initialized = $true - Write-Host "Session initialized via -PathToXML (ephemeral file removed)." - } catch { $lastError = $_ } -} - -if (-not $initialized) { - Write-Error "Failed to initialize Tanium session. Last error: $($lastError.Exception.Message)" - throw -} - -# --- Retrieve & display groups --- -Write-Host "Retrieving all Computer Groups..." -$groups = Get-ComputerGroup -All - -if (Get-Command Out-GridView -ErrorAction SilentlyContinue) { - $groups | Out-GridView -Title 'Tanium Computer Groups' -} else { - Write-Warning "Out-GridView not available; showing a console table instead." - $groups | Format-Table -Auto -} diff --git a/API/ComputerGroup - New.ps1 b/API/ComputerGroup - New.ps1 deleted file mode 100644 index 4d37c4a..0000000 --- a/API/ComputerGroup - New.ps1 +++ /dev/null @@ -1,115 +0,0 @@ -<# -.SYNOPSIS -Initialize Tanium session from config.json, then create Computer Groups only if they do not already exist. -#> - -# ========================= -# 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 - - # Values (fallback to environment variables) - $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 -} - -try { - # ========================= - # Block 3 - Ensure Computer Groups exist - # ========================= - - # Hashtable of groups to ensure: Name => Filter text - $ComputerGroups = @{ - "David_LTSC2019" = "(Computer Name contains 2019)" - "David_LTSC2021" = "(Computer Name contains 2021)" - "David_LTSC2024" = "(Computer Name contains 2024)" - } - - # Default Content Set (id = 0) – change if needed - $contentSetDefault = [pscustomobject]@{ id = 0 } - - Write-Host "Ensuring Computer Groups exist (create if missing)..." - foreach ($kv in $ComputerGroups.GetEnumerator()) { - $name = $kv.Key - $filterText = $kv.Value - - try { - $existing = Get-ComputerGroup -Name $name -ErrorAction SilentlyContinue - if ($existing) { - Write-Host "Group '$name' already exists (Id: $($existing.id)). Skipping." - continue - } - - Write-Host "Creating group: '$name' with filter: $filterText" - New-ComputerGroup ` - -Name $name ` - -Type 0 ` - -Text $filterText ` - -Content_Set $contentSetDefault ` - -Filter_Flag $true ` - -Management_Rights_Flag $true - - Write-Host "Created group: '$name'." - } - catch { - Write-Error "Failed processing group '$name'. Details: $($_.Exception.Message)" - } - } - -} -finally { - # ========================= - # Block 4 - 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)" - } -} diff --git a/API/Deploy - Create.ps1 b/API/Deploy - Create.ps1 deleted file mode 100644 index 414b3d1..0000000 --- a/API/Deploy - Create.ps1 +++ /dev/null @@ -1,196 +0,0 @@ -<# -.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 diff --git a/API/Deploy - Get.ps1 b/API/Deploy - Get.ps1 deleted file mode 100644 index 995f698..0000000 --- a/API/Deploy - Get.ps1 +++ /dev/null @@ -1,59 +0,0 @@ -<# -.SYNOPSIS -List Tanium Deploy Software Packages using Get-DeploySoftware. -Reads URL/token from config.json, initializes the session, then queries by: - - All | ByName | ByID | ByVendor | ByCommand | NameRegex -and displays results in Out-GridView (fallback to console table). -#> - -# ========================= -# Block 1 - Prerequisites -# ========================= -$ErrorActionPreference = 'Stop' -try { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 } catch {} -Import-Module Redden-TanREST -Force - -# ========================= -# Block 2 - Load config & init session -# ========================= -$configPath = Join-Path $PSScriptRoot 'config.json' -$TempXml = Join-Path $env:TEMP 'tanium-session-tmp.apicred' - -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 -$TaniumToken = $config.TaniumApiToken - -if ([string]::IsNullOrWhiteSpace($TaniumUrl) -or [string]::IsNullOrWhiteSpace($TaniumToken)) { - throw "Both TaniumUrl and TaniumApiToken must be provided (config.json or environment variables)." -} -if ($TaniumUrl -match '^https?://') { - $TaniumUrl = $TaniumUrl -replace '^https?://','' -replace '/+$','' - Write-Host "Normalized TaniumUrl to host: $TaniumUrl" -} - -$ExportObject = @{ - baseURI = $TaniumUrl - token = ($TaniumToken | ConvertTo-SecureString -AsPlainText -Force) -} -$ExportObject | Export-Clixml -Path $TempXml - -Write-Host "Initializing Tanium session..." -Initialize-TaniumSession -PathToXML $TempXml -Write-Host "Tanium session initialized." - -# ========================= -# Block 3 - Choose query mode -# ========================= -Get-DeploySoftware -All | Out-GridView - -# ========================= -# Block 5 - Cleanup -# ========================= -if (Test-Path $TempXml) { - Remove-Item $TempXml -Force -ErrorAction SilentlyContinue - Write-Host "Temporary CLIXML removed: $TempXml" -} - diff --git a/API/Interact - GetQuestion.ps1 b/API/Interact - GetQuestion.ps1 deleted file mode 100644 index 66dded3..0000000 --- a/API/Interact - GetQuestion.ps1 +++ /dev/null @@ -1,93 +0,0 @@ -<# -.SYNOPSIS -Initialize Tanium session from config.json, ensure computer groups exist (create if missing), -then ask an Interact question and display results in Out-GridView. - -.NOTES -- Keep config.json out of version control. -#> - -# ========================= -# 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' - -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 - - # Values (fallback to environment variables) - $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 - $TempXml = Join-Path $env:TEMP 'tanium-session-tmp.apicred' - $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 - Interact question + Out-GridView (no flattener) -# ========================= - -$canonicalText = 'Get Computer Name and IP Address from all machines with Operating System contains Windows' -$minResponsePct = 95 -$expireSeconds = 1200 - -Write-Host "Asking Interact question..." -$result = Get-InteractQuestionResult ` - -CanonicalText $canonicalText ` - -MinResponsePercent $minResponsePct ` - -ExpireSeconds $expireSeconds ` - -Verbose - -$result | Out-GridView -Title 'Windows endpoints' - - - -# ========================= -# Block 5 - 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)" -} diff --git a/API/Package - Create.ps1 b/API/Package - Create.ps1 deleted file mode 100644 index 8ec703e..0000000 --- a/API/Package - Create.ps1 +++ /dev/null @@ -1,208 +0,0 @@ -<# -.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\ 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)" -} diff --git a/API/Package - Get.ps1 b/API/Package - Get.ps1 deleted file mode 100644 index 4ddbfca..0000000 --- a/API/Package - Get.ps1 +++ /dev/null @@ -1,139 +0,0 @@ -<# -.SYNOPSIS -Initialize Tanium session from config.json, then list Tanium Packages -(using Get-TaniumPackage in several modes) and show them in Out-GridView. -#> - -# ========================= -# 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" - } - - # 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 - Pick your query mode -# ========================= -# Choose ONE mode: 'All' | 'ByName' | 'ByID' | 'NameRegex' | 'ByParam' -$QueryMode = 'All' -$IncludeHidden = $false - -# Fill only the variables needed by the chosen mode: -$ByName_Name = 'My Awesome Package' -$ByID_Id = 123 -$NameRegex_Pattern= '.*Awesome.*' -$ByParam_Field = 'command' # e.g. 'command' -$ByParam_Operator = 'RegexMatch' # e.g. 'Equal' | 'RegexMatch' -$ByParam_Value = '.*cleanup\.vbs' # regex string if using RegexMatch -$ByParam_Type = 'String' # 'String' | 'Version' | 'Numeric' | 'IPAddress' | 'Date' | 'DataSize' | 'NumericInteger' - -# ========================= -# Block 4 - Retrieve packages -# ========================= -try { - switch ($QueryMode) { - 'All' { - Write-Host "Retrieving ALL packages..." - $packages = Get-TaniumPackage -All -IncludeHidden:$IncludeHidden - } - 'ByName' { - Write-Host "Retrieving package by name: $ByName_Name" - $packages = Get-TaniumPackage -Name $ByName_Name -IncludeHidden:$IncludeHidden - } - 'ByID' { - Write-Host "Retrieving package by ID: $ByID_Id" - $packages = Get-TaniumPackage -ID $ByID_Id -IncludeHidden:$IncludeHidden - } - 'NameRegex' { - Write-Host "Retrieving packages by NameRegex: $NameRegex_Pattern" - $packages = Get-TaniumPackage -NameRegex $NameRegex_Pattern -IncludeHidden:$IncludeHidden - } - 'ByParam' { - Write-Host "Retrieving packages by field filter: $ByParam_Field $ByParam_Operator $ByParam_Value ($ByParam_Type)" - $packages = Get-TaniumPackage -Field $ByParam_Field -Operator $ByParam_Operator -Value $ByParam_Value -Type $ByParam_Type -IncludeHidden:$IncludeHidden - } - default { - throw "Unknown QueryMode '$QueryMode'. Use: All | ByName | ByID | NameRegex | ByParam." - } - } - - if (-not $packages) { - Write-Warning "No packages found." - } - - # Try to present common fields; unknown props will appear blank (that's fine) - $view = $packages | Select-Object ` - @{n='id';e={$_.id}}, - @{n='name';e={$_.name}}, - @{n='display_name';e={$_.display_name}}, - @{n='command';e={$_.command}}, - @{n='expire_seconds';e={$_.expire_seconds}}, - @{n='command_timeout';e={$_.command_timeout}}, - @{n='content_set_id';e={$_.content_set.id}}, - @{n='hidden';e={$_.hidden}} - - if (Get-Command Out-GridView -ErrorAction SilentlyContinue) { - $view | Out-GridView -Title "Tanium Packages ($QueryMode)" - } else { - Write-Warning "Out-GridView not available; showing a console table instead." - $view | Format-Table -Auto - } -} -catch { - Write-Error "Failed to retrieve/display packages. Details: $($_.Exception.Message)" -} - -# ========================= -# Block 5 - 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)" -} diff --git a/API/RBAC_CreateComputerGroup_graphql.ps1 b/API/RBAC_CreateComputerGroup_graphql.ps1 deleted file mode 100644 index a717756..0000000 --- a/API/RBAC_CreateComputerGroup_graphql.ps1 +++ /dev/null @@ -1,218 +0,0 @@ -<# -.SYNOPSIS -Create or delete a Tanium Computer Group via Gateway GraphQL. - -.DESCRIPTION -- CREATE: filter "Computer Name STARTS_WITH " (usable as Computer Management Group; optional Content Set). -- DELETE: delete a Computer Group by its Tanium ID. -- Reads URL/token from config.json (same folder) unless -Url/-Token are provided. -- Optional TLS bypass for lab with -SkipCertCheck. - -.USAGE (examples) -# Create a group (no defaults; you MUST pass -GroupName and -Prefix) -.\Create-ComputerGroup.ps1 -GroupName "LAB - starts with LAB" -Prefix "LAB" -MrEnabled:$true -.\Create-ComputerGroup.ps1 -GroupName "LAB - starts with LAB" -Prefix "LAB" -ContentSetName "My Content Set" - -# Delete by ID -.\Create-ComputerGroup.ps1 -Delete -Id "12345" - -# Override URL/token -.\Create-ComputerGroup.ps1 -Url tanium.pp.dktinfra.io -Token 'token-xxxx' -GroupName "LAB ..." -Prefix "LAB" - -# Raw JSON (debug) -.\Create-ComputerGroup.ps1 -GroupName "LAB ..." -Prefix "LAB" -Raw -#> - -param( - [string]$Url, - [string]$Token, - [switch]$SkipCertCheck, - - # CREATE params (no defaults; both required for creation) - [string]$GroupName, - [string]$Prefix, - [bool] $MrEnabled = $true, - [string]$ContentSetName, - - # DELETE params - [switch]$Delete, - [string]$Id, - - [switch]$Raw -) - -$ErrorActionPreference = 'Stop' -try { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 } catch {} - -function Show-ShortHelp { - Write-Host "" - Write-Host "Create mode (requires -GroupName and -Prefix):" -ForegroundColor Cyan - Write-Host " .\Create-ComputerGroup.ps1 -GroupName 'LAB - starts with LAB' -Prefix 'LAB' [-MrEnabled:`$true] [-ContentSetName 'My Content Set']" -ForegroundColor Gray - Write-Host "" - Write-Host "Delete mode (requires -Delete and -Id):" -ForegroundColor Cyan - Write-Host " .\Create-ComputerGroup.ps1 -Delete -Id '12345'" -ForegroundColor Gray - Write-Host "" - Write-Host "Common options: -Url -Token -SkipCertCheck -Raw" -ForegroundColor DarkGray -} - -# ---------- Helpers ---------- -function Get-GatewayUri { - param([Parameter(Mandatory)][string]$HostLike) - $h = $HostLike.Trim() - if ($h -match '^https?://') { $h = $h -replace '^https?://','' } - $h = $h.TrimEnd('/') - if ([string]::IsNullOrWhiteSpace($h)) { throw 'TaniumUrl empty after normalization.' } - "https://$h/plugin/products/gateway/graphql" -} - -# TLS bypass for Windows PowerShell 5.1 (temporary, restored after call) -$script:__oldCb = $null -function Enter-InsecureTls { - param([switch]$Enable) - if (-not $Enable) { return } - $script:__oldCb = [System.Net.ServicePointManager]::ServerCertificateValidationCallback - $cb = [System.Net.Security.RemoteCertificateValidationCallback]{ param($s,$c,$ch,$e) $true } - [System.Net.ServicePointManager]::ServerCertificateValidationCallback = $cb -} -function Exit-InsecureTls { - if ($script:__oldCb -ne $null) { - [System.Net.ServicePointManager]::ServerCertificateValidationCallback = $script:__oldCb - $script:__oldCb = $null - } -} - -# ---------- Load config if needed ---------- -$BaseDir = if ($PSScriptRoot) { $PSScriptRoot } else { $pwd.Path } -$configPath = Join-Path $BaseDir 'config.json' -if (-not $Url -or -not $Token) { - if (-not (Test-Path $configPath)) { - throw "Missing -Url/-Token and config.json not found: $configPath" - } - $cfg = Get-Content -Path $configPath -Raw | ConvertFrom-Json - if (-not $Url) { $Url = [string]$cfg.TaniumUrl } - if (-not $Token) { $Token = [string]$cfg.TaniumApiToken } - if (-not $PSBoundParameters.ContainsKey('SkipCertCheck')) { $SkipCertCheck = [bool]$cfg.SkipCertificateCheck } -} - -# ---------- Endpoint & headers ---------- -$gateway = Get-GatewayUri -HostLike $Url -$headers = @{ 'Content-Type' = 'application/json'; session = $Token } - -# ---------- GraphQL mutations ---------- -$Create_WithContentSet = @' -mutation createGroup($name: String!, $mrEnabled: Boolean!, $prefix: String!, $contentSetName: String!) { - computerGroupCreate( - input: { - name: $name - managementRightsEnabled: $mrEnabled - contentSetRef: { name: $contentSetName } - filter: { - sensor: { name: "Computer Name" } - op: STARTS_WITH - value: $prefix - } - } - ) { - group { id name } - error { message } - } -} -'@ - -$Create_NoContentSet = @' -mutation createGroup($name: String!, $mrEnabled: Boolean!, $prefix: String!) { - computerGroupCreate( - input: { - name: $name - managementRightsEnabled: $mrEnabled - filter: { - sensor: { name: "Computer Name" } - op: STARTS_WITH - value: $prefix - } - } - ) { - group { id name } - error { message } - } -} -'@ - -$Delete_ById = @' -mutation deleteComputerGroup($id: ID!) { - computerGroupDelete(ref: { id: $id }) { - id - error { message } - } -} -'@ - -# ---------- Mode selection & validation ---------- -if ($Delete) { - if ([string]::IsNullOrWhiteSpace($Id)) { - Write-Warning "Missing -Id for deletion." - Show-ShortHelp - return - } - $Query = $Delete_ById - $Variables = @{ id = $Id } - $OpName = 'deleteComputerGroup' -} -else { - if ([string]::IsNullOrWhiteSpace($GroupName) -or [string]::IsNullOrWhiteSpace($Prefix)) { - Write-Warning "Missing -GroupName and/or -Prefix for creation." - Show-ShortHelp - return - } - $useCS = -not [string]::IsNullOrWhiteSpace($ContentSetName) - $Query = if ($useCS) { $Create_WithContentSet } else { $Create_NoContentSet } - $Variables = @{ name = $GroupName; mrEnabled = $MrEnabled; prefix = $Prefix } - if ($useCS) { $Variables.contentSetName = $ContentSetName } - $OpName = 'createGroup' -} - -# ---------- Execute ---------- -$bodyObj = @{ query = $Query; variables = $Variables; operationName = $OpName } -$bodyJson = $bodyObj | ConvertTo-Json -Depth 10 - -$resp = $null -$ps7 = ($PSVersionTable.PSVersion.Major -ge 7) -if ($ps7 -and $SkipCertCheck) { - $resp = Invoke-RestMethod -SkipCertificateCheck -Method Post -Uri $gateway -Headers $headers -ContentType 'application/json' -Body $bodyJson -} -else { - try { - Enter-InsecureTls -Enable:$SkipCertCheck - $resp = Invoke-RestMethod -Method Post -Uri $gateway -Headers $headers -ContentType 'application/json' -Body $bodyJson - } - finally { Exit-InsecureTls } -} - -# ---------- Output ---------- -if ($Raw) { $resp | ConvertTo-Json -Depth 12; return } - -if ($resp.errors) { - Write-Error ("GraphQL errors: " + (($resp.errors | ForEach-Object { $_.message }) -join '; ')) - return -} - -if ($Delete) { - $del = $resp.data.computerGroupDelete - if ($del.error -and $del.error.message) { - Write-Error ("Delete failed: {0}" -f $del.error.message) - } elseif ($del.id) { - Write-Host ("Deleted group ID: {0}" -f $del.id) -ForegroundColor Green - } else { - Write-Warning "No confirmation returned. Use -Raw to inspect the full response." - } -} -else { - $crt = $resp.data.computerGroupCreate - if ($crt.error -and $crt.error.message) { - Write-Error ("Create failed: {0}" -f $crt.error.message) - } elseif ($crt.group) { - Write-Host ("Created group: {0} (ID: {1})" -f $crt.group.name, $crt.group.id) -ForegroundColor Green - } else { - Write-Warning "No group returned. Use -Raw to inspect the full response." - } -} diff --git a/API/RBAC_ExportRole_Redden-TanREST.ps1 b/API/RBAC_ExportRole_Redden-TanREST.ps1 deleted file mode 100644 index c7020ba..0000000 --- a/API/RBAC_ExportRole_Redden-TanREST.ps1 +++ /dev/null @@ -1,89 +0,0 @@ -#requires -Version 7.0 -<# -.SYNOPSIS -Initialize Tanium (Redden-TanREST) from config.json, then -export all roles whose name starts with a given prefix (default: CASH). - -.PARAMETER Prefix -Role name prefix to match (prefix match, case-insensitive). Default: CASH. - -.PARAMETER OutputFolder -Destination folder for JSON exports. Default: %TEMP%\RBAC -#> - -param( - [string]$Prefix = 'CASH', - [string]$OutputFolder = "$env:TEMP\RBAC" -) - -$ErrorActionPreference = 'Stop' -try { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 } catch {} -Import-Module Redden-TanREST -Force - -# --- Load config -$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 -replace '^https?://','').TrimEnd('/') -$TaniumTok = $config.TaniumApiToken -if ([string]::IsNullOrWhiteSpace($TaniumUrl) -or [string]::IsNullOrWhiteSpace($TaniumTok)) { - throw "Both TaniumUrl and TaniumApiToken must be provided in $ConfigPath." -} - -# --- Prepare output -if (-not (Test-Path $OutputFolder)) { New-Item -ItemType Directory -Path $OutputFolder -Force | Out-Null } - -# --- Temporary CLIXML for Initialize-TaniumSession -$TempXml = Join-Path $env:TEMP ("tanium-session-{0}.apicred" -f ([guid]::NewGuid().ToString('N'))) -@{ baseURI = $TaniumUrl; token = ($TaniumTok | ConvertTo-SecureString -AsPlainText -Force) } | - Export-Clixml -Path $TempXml -Force - -Write-Host "Initializing Tanium session..." -try { - Initialize-TaniumSession -PathToXML $TempXml | Out-Null - Write-Host "Session OK." - - # ---------- GET roles starting with prefix ---------- - # Prefer server-side regex; fall back to client-side if module/endpoint refuses inline (?i) - $regex = "(?i)^$([regex]::Escape($Prefix))" - $roles = $null - try { $roles = Get-Role -NameRegex $regex } catch { $roles = $null } - if (-not $roles) { - # fallback: pull all and filter locally - $roles = Get-Role -All | Where-Object { $_.name -match $regex -or $_.Name -match $regex } - } - - if (-not $roles) { - Write-Warning "No roles found starting with '$Prefix'." - return - } - - # ---------- Export each role ---------- - $exported = @() - foreach ($r in @($roles)) { - $id = if ($r.PSObject.Properties.Name -contains 'id') { $r.id } elseif ($r.PSObject.Properties.Name -contains 'ID') { $r.ID } else { $null } - $name = if ($r.PSObject.Properties.Name -contains 'name') { $r.name } elseif ($r.PSObject.Properties.Name -contains 'Name') { $r.Name } else { $null } - if (-not $name) { continue } - - try { - Export-RoleToJSON -RoleName $name -OutputFolder $OutputFolder -SkipReInitialize:$true -ErrorAction Stop - Write-Host ("✓ Exported: {0} (ID: {1})" -f $name, $id) - $exported += [pscustomobject]@{ Id=$id; Name=$name } - } - catch { - Write-Warning ("Export failed for role '{0}' (ID: {1}) — {2}" -f $name, $id, $_.Exception.Message) - } - } - - if ($exported) { - Write-Host "`nSummary:" - $exported | Sort-Object Name | Format-Table Id,Name -AutoSize - Write-Host "`nJSON files in: $OutputFolder" - } -} -finally { - if (Test-Path $TempXml) { - Remove-Item $TempXml -Force -ErrorAction SilentlyContinue - Write-Host "Temporary CLIXML removed: $TempXml" - } -} diff --git a/API/RBAC_ImportRole_Redden-TanREST KO.ps1 b/API/RBAC_ImportRole_Redden-TanREST KO.ps1 deleted file mode 100644 index 7569b66..0000000 --- a/API/RBAC_ImportRole_Redden-TanREST KO.ps1 +++ /dev/null @@ -1,264 +0,0 @@ -#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": { "": { "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":"", - "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 - } - } -} diff --git a/API/RBAC_ListComputerGroup_GraphQL.ps1 b/API/RBAC_ListComputerGroup_GraphQL.ps1 deleted file mode 100644 index 56d8011..0000000 --- a/API/RBAC_ListComputerGroup_GraphQL.ps1 +++ /dev/null @@ -1,219 +0,0 @@ -# List-ComputerGroups.ps1 — robust fallback + HTTP 400 handling + introspection - -param( - [string]$Url, - [string]$Token, - [switch]$SkipCertCheck, - [int]$PageSize = 200, - [string]$NameLike, - [switch]$Raw, - [switch]$Grid, - [string]$ExportCsv, - [switch]$Introspect -) - -$ErrorActionPreference = 'Stop' -try { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 } catch {} - -function Get-GatewayUri { - param([Parameter(Mandatory)][string]$HostLike) - $h = $HostLike.Trim() - if ($h -match '^https?://') { $h = $h -replace '^https?://','' } - $h = $h.TrimEnd('/') - if ([string]::IsNullOrWhiteSpace($h)) { throw 'TaniumUrl empty after normalization.' } - "https://$h/plugin/products/gateway/graphql" -} - -# TLS bypass for Windows PowerShell 5.1 -$script:__oldCb = $null -function Enter-InsecureTls { param([switch]$Enable) - if (-not $Enable) { return } - $script:__oldCb = [System.Net.ServicePointManager]::ServerCertificateValidationCallback - $cb = [System.Net.Security.RemoteCertificateValidationCallback]{ param($s,$c,$ch,$e) $true } - [System.Net.ServicePointManager]::ServerCertificateValidationCallback = $cb -} -function Exit-InsecureTls { - if ($script:__oldCb -ne $null) { - [System.Net.ServicePointManager]::ServerCertificateValidationCallback = $script:__oldCb - $script:__oldCb = $null - } -} - -# Load config if needed -$BaseDir = if ($PSScriptRoot) { $PSScriptRoot } else { $pwd.Path } -$configPath = Join-Path $BaseDir 'config.json' -if (-not $Url -or -not $Token) { - if (-not (Test-Path $configPath)) { throw "Missing -Url/-Token and config.json not found: $configPath" } - $cfg = Get-Content -Path $configPath -Raw | ConvertFrom-Json - if (-not $Url) { $Url = [string]$cfg.TaniumUrl } - if (-not $Token) { $Token = [string]$cfg.TaniumApiToken } - if (-not $PSBoundParameters.ContainsKey('SkipCertCheck')) { $SkipCertCheck = [bool]$cfg.SkipCertificateCheck } -} - -$gateway = Get-GatewayUri -HostLike $Url -$headers = @{ 'Content-Type' = 'application/json'; session = $Token } - -# ---- Introspection (optional) -if ($Introspect) { -$IntrospectQuery = @' -query { - __type(name: "ComputerGroup") { - name - fields { name type { kind name ofType { kind name } } } - } -} -'@ - $body = @{ query = $IntrospectQuery } | ConvertTo-Json -Depth 6 - $resp = $null - $ps7 = ($PSVersionTable.PSVersion.Major -ge 7) - if ($ps7 -and $SkipCertCheck) { - $resp = Invoke-RestMethod -SkipCertificateCheck -Method Post -Uri $gateway -Headers $headers -Body $body - } else { - try { Enter-InsecureTls -Enable:$SkipCertCheck; $resp = Invoke-RestMethod -Method Post -Uri $gateway -Headers $headers -Body $body } - finally { Exit-InsecureTls } - } - if ($resp.errors) { Write-Error (($resp.errors | ForEach-Object message) -join '; '); return } - $resp.data.__type.fields | Select-Object name,@{n='type';e={$_.type.name ?? $_.type.ofType.name}} | Format-Table -AutoSize - return -} - -# ---- Queries (order = safest → richer) -$Q_Basic = @' -query listComputerGroups($first: Int, $after: Cursor) { - computerGroups(first: $first, after: $after) { - edges { node { id name managementRightsEnabled } } - pageInfo { hasNextPage endCursor } - } -} -'@ - -$Q_ContentSet = @' -query listComputerGroups($first: Int, $after: Cursor) { - computerGroups(first: $first, after: $after) { - edges { node { id name managementRightsEnabled contentSet { name } } } - pageInfo { hasNextPage endCursor } - } -} -'@ - -$Q_ContentSetV2 = @' -query listComputerGroups($first: Int, $after: Cursor) { - computerGroups(first: $first, after: $after) { - edges { node { id name managementRightsEnabled contentSetV2 { name } } } - pageInfo { hasNextPage endCursor } - } -} -'@ - -$Q_Filter = @' -query listComputerGroups($first: Int, $after: Cursor) { - computerGroups(first: $first, after: $after) { - edges { node { - id name managementRightsEnabled - filter { memberOf { name } sensor { name } op value } - } } - pageInfo { hasNextPage endCursor } - } -} -'@ - -$queries = @($Q_Basic, $Q_ContentSet, $Q_ContentSetV2, $Q_Filter) - -function Invoke-Gql { - param([string]$Query, [hashtable]$Vars, [string]$OpName) - $body = @{ query = $Query; variables = $Vars; operationName = $OpName } | ConvertTo-Json -Depth 10 - $ps7 = ($PSVersionTable.PSVersion.Major -ge 7) - try { - if ($ps7 -and $SkipCertCheck) { - return Invoke-RestMethod -SkipCertificateCheck -Method Post -Uri $gateway -Headers $headers -ContentType 'application/json' -Body $body - } else { - Enter-InsecureTls -Enable:$SkipCertCheck - return Invoke-RestMethod -Method Post -Uri $gateway -Headers $headers -ContentType 'application/json' -Body $body - } - } - catch { - # If server returned HTTP 400 with a JSON GraphQL error, parse it and return so we can fallback. - $we = $_.Exception - if ($we.Response) { - try { - $sr = New-Object IO.StreamReader($we.Response.GetResponseStream()) - $txt = $sr.ReadToEnd() - if ($txt) { return ($txt | ConvertFrom-Json) } - } catch { } - } - throw # non-GraphQL error -> bubble up - } - finally { Exit-InsecureTls } -} - -# ---- Fetch with fallback chain -$allEdges = New-Object System.Collections.Generic.List[object] -$cursor = $null -$qIndex = 0 -$opName = 'listComputerGroups' - -while ($true) { - $vars = @{ first = $PageSize; after = $cursor } - $resp = Invoke-Gql -Query $queries[$qIndex] -Vars $vars -OpName $opName - - if ($resp.errors) { - if ($qIndex -lt ($queries.Count - 1)) { - # restart from page 1 with next query - $qIndex++; $cursor = $null; $allEdges.Clear() - continue - } else { - throw ("GraphQL errors: " + (($resp.errors | ForEach-Object { $_.message }) -join '; ')) - } - } - - $edges = $resp.data.computerGroups.edges - if ($edges) { $allEdges.AddRange($edges) } - - $pi = $resp.data.computerGroups.pageInfo - if (-not $pi -or -not $pi.hasNextPage) { break } - $cursor = $pi.endCursor -} - -if ($Raw) { [pscustomobject]@{ total = $allEdges.Count; edges = $allEdges } | ConvertTo-Json -Depth 14; return } -if ($allEdges.Count -eq 0) { Write-Output 'No computer groups returned.'; return } - -function Get-ContentSetName($n) { - if ($n.PSObject.Properties.Match('contentSet').Count -gt 0 -and $n.contentSet) { return $n.contentSet.name } - if ($n.PSObject.Properties.Match('contentSetV2').Count -gt 0 -and $n.contentSetV2) { return $n.contentSetV2.name } - return '' -} -function Get-FilterSummary($n) { - if (-not $n.PSObject.Properties.Match('filter')) { return '' } - $f = $n.filter; if ($null -eq $f) { return '' } - if ($f.memberOf -and $f.memberOf.name) { return ("memberOf: " + $f.memberOf.name) } - if ($f.sensor -and $f.sensor.name) { return ("sensor '" + $f.sensor.name + "' " + $f.op + " '" + $f.value + "'") } - return '' -} - -$rows = foreach ($edge in $allEdges) { - $n = $edge.node - if ($NameLike -and -not ($n.name -match $NameLike)) { continue } - [pscustomobject]@{ - Id = $n.id - Name = $n.name - ManagementRights = $n.managementRightsEnabled - ContentSet = (Get-ContentSetName $n) - Filter = (Get-FilterSummary $n) - } -} - -if (-not $rows) { Write-Output 'No matching groups.'; return } -$rowsSorted = $rows | Sort-Object Name - -if ($ExportCsv) { - try { $rowsSorted | Export-Csv -NoTypeInformation -Encoding UTF8 -Path $ExportCsv; Write-Host "Exported to: $ExportCsv" -ForegroundColor Green } - catch { Write-Warning "CSV export failed: $($_.Exception.Message)" } -} - -if ($Grid) { - $title = "Computer Groups — {0} item(s)" -f ($rowsSorted.Count) - if (Get-Command Out-GridView -ErrorAction SilentlyContinue) { $rowsSorted | Out-GridView -Title $title; return } - else { Write-Warning "Out-GridView not available. On PS7+: Install-Module Microsoft.PowerShell.GraphicalTools" } -} - -$rowsSorted | Format-Table -AutoSize diff --git a/API/RBAC_ListContentset_Rest.ps1 b/API/RBAC_ListContentset_Rest.ps1 deleted file mode 100644 index fe95683..0000000 --- a/API/RBAC_ListContentset_Rest.ps1 +++ /dev/null @@ -1,120 +0,0 @@ -<# -.SYNOPSIS -List Tanium **Content Sets** via the REST API, using Url/Token from `config.json` by default. -Supports optional filter by name (regex), Out‑GridView, and CSV export. - -.USAGE -# Basic (reads config.json in the same folder) -./List-ContentSets.ps1 - -# Filter by name (regex), show grid and export CSV -./List-ContentSets.ps1 -NameLike '^Deploy' -Grid -ExportCsv C:\Temp\content_sets.csv - -# Raw JSON -./List-ContentSets.ps1 -Raw - -# Override Url/Token explicitly -./List-ContentSets.ps1 -Url tanium.pp.dktinfra.io -Token 'token-xxxx' -#> - -param( - [string]$Url, - [string]$Token, - [switch]$SkipCertCheck, - - [string]$NameLike, - [switch]$Raw, - [switch]$Grid, - [string]$ExportCsv -) - -$ErrorActionPreference = 'Stop' -try { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 } catch {} - -# ---------- Helpers ---------- -function New-BaseUri([string]$HostLike) { - $h = $HostLike.Trim() - if ($h -match '^https?://') { $h = $h -replace '^https?://','' } - $h = $h.TrimEnd('/') - if ([string]::IsNullOrWhiteSpace($h)) { throw 'TaniumUrl empty after normalization.' } - "https://$h" -} - -# TLS bypass for Windows PowerShell 5.1 -$script:__oldCb = $null -function Enter-InsecureTls { param([switch]$Enable) - if (-not $Enable) { return } - $script:__oldCb = [System.Net.ServicePointManager]::ServerCertificateValidationCallback - $cb = [System.Net.Security.RemoteCertificateValidationCallback]{ param($s,$c,$ch,$e) $true } - [System.Net.ServicePointManager]::ServerCertificateValidationCallback = $cb -} -function Exit-InsecureTls { - if ($script:__oldCb -ne $null) { - [System.Net.ServicePointManager]::ServerCertificateValidationCallback = $script:__oldCb - $script:__oldCb = $null - } -} - -# ---------- Load config if needed ---------- -$BaseDir = if ($PSScriptRoot) { $PSScriptRoot } else { $pwd.Path } -$configPath = Join-Path $BaseDir 'config.json' -if (-not $Url -or -not $Token) { - if (-not (Test-Path $configPath)) { - throw "Missing -Url/-Token and config.json not found: $configPath" - } - $cfg = Get-Content -Path $configPath -Raw | ConvertFrom-Json - if (-not $Url) { $Url = [string]$cfg.TaniumUrl } - if (-not $Token) { $Token = [string]$cfg.TaniumApiToken } - if (-not $PSBoundParameters.ContainsKey('SkipCertCheck')) { $SkipCertCheck = [bool]$cfg.SkipCertificateCheck } -} - -$Base = New-BaseUri $Url -$Headers = @{ session = $Token; 'Content-Type' = 'application/json' } - -function Invoke-Tanium([string]$Method,[string]$Path,[object]$BodyObj) { - $uri = if ($Path -match '^https?://') { $Path } else { "$Base$Path" } - $body = if ($null -ne $BodyObj) { $BodyObj | ConvertTo-Json -Depth 10 } else { $null } - $ps7 = ($PSVersionTable.PSVersion.Major -ge 7) - if ($ps7 -and $SkipCertCheck) { - return Invoke-RestMethod -SkipCertificateCheck -Method $Method -Uri $uri -Headers $Headers -Body $body - } else { - try { Enter-InsecureTls -Enable:$SkipCertCheck; return Invoke-RestMethod -Method $Method -Uri $uri -Headers $Headers -Body $body } - finally { Exit-InsecureTls } - } -} - -# ---------- Fetch Content Sets ---------- -# Common endpoint for content sets -$resp = Invoke-Tanium GET "/api/v2/content_sets" $null - -# Tanium REST often returns either .data or .items -$contentSets = if ($resp.data) { $resp.data } elseif ($resp.items) { $resp.items } else { $resp } - -if ($Raw) { $contentSets | ConvertTo-Json -Depth 12; return } -if (-not $contentSets) { Write-Output 'No content sets returned.'; return } - -# ---------- Shape output ---------- -$rows = foreach ($cs in $contentSets) { - if ($NameLike -and -not ($cs.name -match $NameLike)) { continue } - [pscustomobject]@{ - Id = $cs.id - Name = $cs.name - Description = $cs.description - } -} - -if (-not $rows) { Write-Output 'No matching content sets.'; return } -$rowsSorted = $rows | Sort-Object Name - -if ($ExportCsv) { - try { $rowsSorted | Export-Csv -NoTypeInformation -Encoding UTF8 -Path $ExportCsv; Write-Host "Exported to: $ExportCsv" -ForegroundColor Green } - catch { Write-Warning "CSV export failed: $($_.Exception.Message)" } -} - -if ($Grid) { - $title = "Content Sets — {0} item(s)" -f ($rowsSorted.Count) - if (Get-Command Out-GridView -ErrorAction SilentlyContinue) { $rowsSorted | Out-GridView -Title $title; return } - else { Write-Warning "Out-GridView not available. On PS7+: Install-Module Microsoft.PowerShell.GraphicalTools" } -} - -$rowsSorted | Format-Table -AutoSize \ No newline at end of file diff --git a/API/RBAC_ListRole_Rest.ps1 b/API/RBAC_ListRole_Rest.ps1 deleted file mode 100644 index f75718a..0000000 --- a/API/RBAC_ListRole_Rest.ps1 +++ /dev/null @@ -1,106 +0,0 @@ -<# -.SYNOPSIS -List Tanium Roles via REST (uses /api/v2/content_set_roles), reading Url/Token from config.json. - -.USAGE -.\List-Roles.ps1 -.\List-Roles.ps1 -NameLike '^Ops' -Grid -ExportCsv C:\Temp\roles.csv -.\List-Roles.ps1 -Raw -#> - -param( - [string]$Url, - [string]$Token, - [switch]$SkipCertCheck, - - [string]$NameLike, - [switch]$Raw, - [switch]$Grid, - [string]$ExportCsv -) - -$ErrorActionPreference = 'Stop' -try { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 } catch {} - -function New-BaseUri([string]$HostLike) { - $h = $HostLike.Trim() - if ($h -match '^https?://') { $h = $h -replace '^https?://','' } - $h = $h.TrimEnd('/') - if ([string]::IsNullOrWhiteSpace($h)) { throw 'TaniumUrl empty after normalization.' } - "https://$h" -} - -# TLS bypass for Windows PowerShell 5.1 -$script:__oldCb = $null -function Enter-InsecureTls { param([switch]$Enable) - if (-not $Enable) { return } - $script:__oldCb = [System.Net.ServicePointManager]::ServerCertificateValidationCallback - $cb = [System.Net.Security.RemoteCertificateValidationCallback]{ param($s,$c,$ch,$e) $true } - [System.Net.ServicePointManager]::ServerCertificateValidationCallback = $cb -} -function Exit-InsecureTls { - if ($script:__oldCb -ne $null) { - [System.Net.ServicePointManager]::ServerCertificateValidationCallback = $script:__oldCb - $script:__oldCb = $null - } -} - -# Load config if needed -$BaseDir = if ($PSScriptRoot) { $PSScriptRoot } else { $pwd.Path } -$configPath = Join-Path $BaseDir 'config.json' -if (-not $Url -or -not $Token) { - if (-not (Test-Path $configPath)) { throw "Missing -Url/-Token and config.json not found: $configPath" } - $cfg = Get-Content -Path $configPath -Raw | ConvertFrom-Json - if (-not $Url) { $Url = [string]$cfg.TaniumUrl } - if (-not $Token) { $Token = [string]$cfg.TaniumApiToken } - if (-not $PSBoundParameters.ContainsKey('SkipCertCheck')) { $SkipCertCheck = [bool]$cfg.SkipCertificateCheck } -} - -$Base = New-BaseUri $Url -$Headers = @{ session = $Token; 'Content-Type' = 'application/json' } - -function Invoke-Tanium([string]$Method,[string]$Path,[object]$BodyObj) { - $uri = if ($Path -match '^https?://') { $Path } else { "$Base$Path" } - $body = if ($null -ne $BodyObj) { $BodyObj | ConvertTo-Json -Depth 10 } else { $null } - $ps7 = ($PSVersionTable.PSVersion.Major -ge 7) - if ($ps7 -and $SkipCertCheck) { - return Invoke-RestMethod -SkipCertificateCheck -Method $Method -Uri $uri -Headers $Headers -Body $body - } else { - try { Enter-InsecureTls -Enable:$SkipCertCheck; return Invoke-RestMethod -Method $Method -Uri $uri -Headers $Headers -Body $body } - finally { Exit-InsecureTls } - } -} - -# ---- Fetch roles (correct endpoint) ---- -$resp = Invoke-Tanium GET "/api/v2/content_set_roles" $null -# Most Tanium APIs return .data here -$roles = if ($resp.data) { $resp.data } elseif ($resp.items) { $resp.items } else { $resp } - -if ($Raw) { $roles | ConvertTo-Json -Depth 12; return } -if (-not $roles) { Write-Output "No roles returned."; return } - -# ---- Shape output ---- -$rows = foreach ($r in $roles) { - if ($NameLike -and -not ($r.name -match $NameLike)) { continue } - [pscustomobject]@{ - Id = $r.id - Name = $r.name - Description = $r.description - } -} - -if (-not $rows) { Write-Output "No matching roles."; return } -$rowsSorted = $rows | Sort-Object Name - -if ($ExportCsv) { - try { $rowsSorted | Export-Csv -NoTypeInformation -Encoding UTF8 -Path $ExportCsv; Write-Host "Exported to: $ExportCsv" -ForegroundColor Green } - catch { Write-Warning "CSV export failed: $($_.Exception.Message)" } -} - -if ($Grid) { - $title = "Roles — {0} item(s)" -f ($rowsSorted.Count) - if (Get-Command Out-GridView -ErrorAction SilentlyContinue) { $rowsSorted | Out-GridView -Title $title; return } - else { Write-Warning "Out-GridView not available. On PS7+: Install-Module Microsoft.PowerShell.GraphicalTools" } -} - -$rowsSorted | Format-Table -AutoSize diff --git a/API/RBAC_ListUserAndGroup_ComputerGroup KO.ps1 b/API/RBAC_ListUserAndGroup_ComputerGroup KO.ps1 deleted file mode 100644 index 5fb5cdb..0000000 --- a/API/RBAC_ListUserAndGroup_ComputerGroup KO.ps1 +++ /dev/null @@ -1,204 +0,0 @@ -#requires -Version 7.0 -<# -.SYNOPSIS -Liste les Computer Groups (Management Rights) effectifs par UTILISATEUR et par USER GROUP, -en affichant les NOMS (pas les mrgroup_*). -- Auth depuis config.json (TaniumUrl, TaniumApiToken) via CLIXML -> Initialize-TaniumSession -- Déplie .group.id avec Get-MRGroupsFromGroup et mappe ID->Nom via Get-ManagementRightsGroup (fallback REST) -#> - -# ========================= -# Block 1 - Prérequis -# ========================= -$ErrorActionPreference = 'Stop' -try { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 } catch {} -Import-Module Redden-TanREST -Force - -# ========================= -# Block 2 - Chargement config & init session -# ========================= -$configPath = Join-Path $PSScriptRoot 'config.json' -$TempXml = Join-Path $env:TEMP 'tanium-session-tmp.apicred' - -if (-not (Test-Path $configPath -PathType Leaf)) { - throw "Configuration file not found: $configPath (expected: TaniumUrl, TaniumApiToken)" -} - -Write-Host "Reading configuration from: $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." -} -if ($TaniumUrl -match '^https?://') { - $TaniumUrl = $TaniumUrl -replace '^https?://','' -replace '/+$','' - Write-Host "Normalized TaniumUrl to host: $TaniumUrl" -} - -$ExportObject = @{ - baseURI = $TaniumUrl - token = ($TaniumToken | ConvertTo-SecureString -AsPlainText -Force) -} -$ExportObject | Export-Clixml -Path $TempXml - -Write-Host "Initializing Tanium session..." -Initialize-TaniumSession -PathToXML $TempXml -Write-Host "Tanium session initialized." - -# ========================= -# Block 3 - Index MR id -> nom (module puis REST fallback) -# ========================= -$Script:MRIndex = @{} -try { - $allMR = Get-ManagementRightsGroup -All -} catch { $allMR = @() } - -if (-not $allMR -or $allMR.Count -eq 0) { - # fallback REST - $baseUri = $TaniumUrl; if ($baseUri -notmatch '^https?://') { $baseUri = "https://$baseUri" } - $headers = @{ - 'Accept' = 'application/json' - 'Content-Type' = 'application/json' - 'X-Api-Token' = $TaniumToken - 'session' = $TaniumToken - } - try { - $resp = Invoke-RestMethod -Method GET -Uri "$baseUri/api/v2/management_rights_groups?limit=5000" -Headers $headers - $allMR = @($resp.items ?? $resp.data ?? $resp) - } catch { - Write-Warning "Could not fetch Management Rights groups via REST: $($_.Exception.Message)" - $allMR = @() - } -} -foreach ($g in $allMR) { - if ($null -ne $g.id) { $Script:MRIndex[[int]$g.id] = [string]$g.name } -} - -# ========================= -# Block 4 - Helpers -# ========================= -function Expand-NamedMRGroups { - <# - .SYNOPSIS - A partir d'un ID de groupe fusionné (.group.id), retourne les Computer Groups *nommés* (id/name). - Utilise Get-MRGroupsFromGroup puis mappe ID->Nom via $Script:MRIndex et filtre mrgroup_*. - #> - param([Parameter(Mandatory)][int]$MergedGroupID) - - if ($MergedGroupID -lt 0) { return @() } - - $items = @() - try { $items = @( Get-MRGroupsFromGroup -ID $MergedGroupID ) } catch { $items = @() } - - $mapped = @() - foreach ($i in $items) { - $id = [int]$i.id - $name = [string]$i.name - if (-not $name -or $name -like 'mrgroup_*') { $name = $Script:MRIndex[$id] } - if ($name) { - $mapped += [pscustomobject]@{ id = $id; name = $name } - } - } - if ($mapped.Count -gt 0) { - $mapped = $mapped | Sort-Object id -Unique - } - return $mapped -} - -function Get-UsersWithComputerGroups { - <# - .SYNOPSIS Récupère Users + leurs Computer Groups effectifs (nommés). - #> - $users = @() - try { $users = @(Get-User -All) } - catch { $users = @(Get-User -Summary) } - - $rows = @() - foreach ($u in $users) { - $uid = [int]($u.id) - $name = [string]($u.display_name ?? $u.displayName ?? $u.name ?? $u.username) - $login = [string]($u.username) - - $mergedId = 0 - try { if ($u.group -and $u.group.id -ne $null) { $mergedId = [int]$u.group.id } } catch {} - - $cgNamed = if ($mergedId -ge 0) { Expand-NamedMRGroups -MergedGroupID $mergedId } else { @() } - $cgNames = $cgNamed.name | Sort-Object -Unique - $cgIds = $cgNamed.id | Sort-Object -Unique - - $rows += [pscustomobject]@{ - id = $uid - name = $name - username = $login - mergedGroup = $mergedId - groupsCount = @($cgNames).Count - groupNames = ($cgNames -join ', ') - groupIDs = ($cgIds -join ', ') - } - } - if ($rows.Count -gt 0) { $rows = $rows | Sort-Object name } - return $rows -} - -function Get-UserGroupsWithComputerGroups { - <# - .SYNOPSIS Récupère User Groups + leurs Computer Groups effectifs (nommés). - #> - $ugs = @(Get-UserGroup -All) - - $rows = @() - foreach ($g in $ugs) { - $gid = [int]($g.id) - $gname = [string]($g.name) - - $mergedId = 0 - try { if ($g.group -and $g.group.id -ne $null) { $mergedId = [int]$g.group.id } } catch {} - - $cgNamed = if ($mergedId -ge 0) { Expand-NamedMRGroups -MergedGroupID $mergedId } else { @() } - $cgNames = $cgNamed.name | Sort-Object -Unique - $cgIds = $cgNamed.id | Sort-Object -Unique - - $rows += [pscustomobject]@{ - id = $gid - name = $gname - mergedGroup = $mergedId - groupsCount = @($cgNames).Count - groupNames = ($cgNames -join ', ') - groupIDs = ($cgIds -join ', ') - } - } - if ($rows.Count -gt 0) { $rows = $rows | Sort-Object name } - return $rows -} - -# ========================= -# Block 5 - Exécution + affichage -# ========================= -Write-Host ">> Gathering Users + Effective Computer Groups..." -ForegroundColor Cyan -$UsersWithCG = Get-UsersWithComputerGroups - -Write-Host ">> Gathering User Groups + Effective Computer Groups..." -ForegroundColor Cyan -$UGsWithCG = Get-UserGroupsWithComputerGroups - -$hasOGV = $null -ne (Get-Command Out-GridView -ErrorAction SilentlyContinue) -if ($hasOGV) { - $UsersWithCG | Out-GridView -Title 'Tanium Users – Effective Computer Groups (by name)' -Wait - $UGsWithCG | Out-GridView -Title 'Tanium User Groups – Effective Computer Groups (by name)' -Wait -} else { - Write-Host "`n=== USERS – EFFECTIVE COMPUTER GROUPS ===" -ForegroundColor Green - $UsersWithCG | Format-Table id,name,username,groupsCount,groupNames -AutoSize - - Write-Host "`n=== USER GROUPS – EFFECTIVE COMPUTER GROUPS ===" -ForegroundColor Green - $UGsWithCG | Format-Table id,name,groupsCount,groupNames -AutoSize - Write-Host "`n(Out-GridView not available; showing tables instead)" -ForegroundColor Yellow -} - -# ========================= -# Block 6 - Cleanup -# ========================= -if (Test-Path $TempXml) { - Remove-Item $TempXml -Force -ErrorAction SilentlyContinue - Write-Host "Temporary CLIXML removed: $TempXml" -} diff --git a/API/RBAC_ListUserAndGroup_Role_Redden-TanREST.ps1 b/API/RBAC_ListUserAndGroup_Role_Redden-TanREST.ps1 deleted file mode 100644 index 204548a..0000000 --- a/API/RBAC_ListUserAndGroup_Role_Redden-TanREST.ps1 +++ /dev/null @@ -1,220 +0,0 @@ -#requires -Version 7.0 -<# -.SYNOPSIS -Affiche les rôles par UTILISATEUR (hors "Tanium Internal*") et/ou par GROUPE, -avec filtres -User et -Group. Sections affichées selon les filtres. -#> - -[CmdletBinding()] -param( - [string[]]$User, # filtre sur display name / username (substring ou wildcard) - [string[]]$Group # filtre sur nom du groupe (substring ou wildcard) -) - -$ErrorActionPreference = 'Stop' -try { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 } catch {} - -# --- Auth depuis config.json --- -$ConfigPath = Join-Path $PSScriptRoot 'config.json' -if (-not (Test-Path $ConfigPath -PathType Leaf)) { - throw "Config introuvable: $ConfigPath (attendu: { `"TaniumUrl`", `"TaniumApiToken`" })" -} -$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, - [hashtable]$Query, - [object]$Body - ) - $b = [System.UriBuilder]("$baseUrl$Path") - if ($Query) { - $nv = [System.Web.HttpUtility]::ParseQueryString([string]::Empty) - foreach ($k in $Query.Keys) { $nv[$k] = [string]$Query[$k] } - $b.Query = $nv.ToString() - } - $uri = $b.Uri.AbsoluteUri - if ($PSBoundParameters.ContainsKey('Body')) { Invoke-RestMethod -Method $Method -Uri $uri -Headers $headers -Body ($Body | ConvertTo-Json -Depth 20) } - else { Invoke-RestMethod -Method $Method -Uri $uri -Headers $headers } -} - -function Get-TaniumItems { - param([Parameter(Mandatory)][object]$Response) - if ($Response.items) { ,@($Response.items) } - elseif ($Response.data) { ,@($Response.data) } - elseif ($Response.users) { ,@($Response.users) } - elseif ($Response.user_groups) { ,@($Response.user_groups) } - else { ,@($Response) } -} - -# helper: match substring/wildcard, case-insensitive -function Test-Match { - param([string]$Text, [string[]]$Patterns) - if (-not $Patterns -or $Patterns.Count -eq 0) { return $true } - foreach ($p in $Patterns) { - if ([string]::IsNullOrWhiteSpace($p)) { continue } - $pat = $p - if ($pat -notmatch '[\*\?\[\]]') { $pat = "*$pat*" } # ajoute wildcards si absent - if ($Text -like $pat -or $Text -like $pat.ToLower() -or $Text -like $pat.ToUpper()) { return $true } - } - return $false -} - -# Déterminer quelles sections afficher -$hasUserFilter = $PSBoundParameters.ContainsKey('User') -and $User -and $User.Count -gt 0 -$hasGroupFilter = $PSBoundParameters.ContainsKey('Group') -and $Group -and $Group.Count -gt 0 -if ($hasUserFilter -and -not $hasGroupFilter) { $showUsers = $true; $showGroups = $false } -elseif ($hasGroupFilter -and -not $hasUserFilter) { $showUsers = $false; $showGroups = $true } -else { $showUsers = $true; $showGroups = $true } # aucun filtre OU les deux => montrer les deux - -# --- Rôles (nécessaire pour libellés) --- -Write-Host ">> Récupère la liste des rôles..." -ForegroundColor Cyan -$rolesAll = Get-TaniumItems (Invoke-TaniumApi -Method GET -Path '/api/v2/content_set_roles' -Query @{ limit = 5000 }) -$roleIndex = @{}; foreach ($r in $rolesAll) { if ($null -ne $r.id) { $roleIndex[[int]$r.id] = [string]$r.name } } - -function Format-RoleLabel { - param([int]$Id, [string]$Name) - if ([string]::IsNullOrWhiteSpace($Name)) { $Name = $roleIndex[$Id] } - if ([string]::IsNullOrWhiteSpace($Name)) { "RoleID:$Id" } else { "RoleID:$Id ($Name)" } -} - -# --- Utilisateurs (+ memberships) -------------------------------------------- -$usersWithRoles = @() -if ($showUsers) { - Write-Host ">> Récupère les utilisateurs..." -ForegroundColor Cyan - $usersAll = Get-TaniumItems (Invoke-TaniumApi -Method GET -Path '/api/v2/users' -Query @{ limit = 5000 }) - - $users = $usersAll | Where-Object { - $disp = $_.display_name ?? $_.displayName ?? $_.name ?? $_.username - -not ($disp -like 'Tanium Internal*') -and ( - (Test-Match -Text $disp -Patterns $User) -or (Test-Match -Text $_.username -Patterns $User) - ) - } - - Write-Host ">> Récupère les memberships (User<->Role)..." -ForegroundColor Cyan - $userRoleMships = Get-TaniumItems (Invoke-TaniumApi -Method GET -Path '/api/v2/content_set_role_memberships' -Query @{ limit = 50000 }) - - # Index users - $userIndex = @{} - foreach ($u in $users) { - $userIndex[[int]$u.id] = [pscustomobject]@{ - ID = [int]$u.id - Name = $u.display_name ?? $u.displayName ?? $u.name ?? $u.username - Username = $u.username - Email = $u.email - } - } - - # Rôles par user - $rolesByUser = @{} - foreach ($m in $userRoleMships) { - if ($null -eq $m.user -or $null -eq $m.content_set_role) { continue } - $uid = [int]$m.user.id - if (-not $userIndex.ContainsKey($uid)) { continue } # filtré/exclu - $rid = [int]$m.content_set_role.id - $rname = [string]$m.content_set_role.name - $label = Format-RoleLabel -Id $rid -Name $rname - if (-not $rolesByUser.ContainsKey($uid)) { $rolesByUser[$uid] = @() } - $rolesByUser[$uid] += $label - } - - $usersWithRoles = $userIndex.GetEnumerator() | - ForEach-Object { - $uid = $_.Key - $info = $_.Value - $roles = @() - if ($rolesByUser.ContainsKey($uid)) { - $roles = $rolesByUser[$uid] | Where-Object { $_ } | Sort-Object -Unique - } - [pscustomobject]@{ - ID = $info.ID - Nom = $info.Name - Username = $info.Username - RolesCount = $roles.Count - Roles = ($roles -join ', ') - } - } | - Sort-Object -Property Nom -} - -# --- Groupes (+ memberships) -------------------------------------------------- -$groupsWithRoles = @() -if ($showGroups) { - Write-Host ">> Récupère les groupes..." -ForegroundColor Cyan - $groupsAll = Get-TaniumItems (Invoke-TaniumApi -Method GET -Path '/api/v2/user_groups' -Query @{ limit = 5000 }) - $groups = $groupsAll | Where-Object { - $gname = $_.name ?? $_.display_name ?? $_.displayName - Test-Match -Text $gname -Patterns $Group - } - - Write-Host ">> Récupère les memberships (Group<->Role)..." -ForegroundColor Cyan - $groupRoleMships = Get-TaniumItems (Invoke-TaniumApi -Method GET -Path '/api/v2/content_set_user_group_role_memberships' -Query @{ limit = 50000 }) - - # Index groupes - $groupIndex = @{} - foreach ($g in $groups) { - $groupIndex[[int]$g.id] = [pscustomobject]@{ - ID = [int]$g.id - Name = $g.name ?? $g.display_name ?? $g.displayName - } - } - - # Rôles par groupe - $rolesByGroup = @{} - foreach ($m in $groupRoleMships) { - if ($null -eq $m.user_group -or $null -eq $m.content_set_role) { continue } - $gid = [int]$m.user_group.id - if (-not $groupIndex.ContainsKey($gid)) { continue } # filtré/exclu - $rid = [int]$m.content_set_role.id - $rname = [string]$m.content_set_role.name - $label = Format-RoleLabel -Id $rid -Name $rname - if (-not $rolesByGroup.ContainsKey($gid)) { $rolesByGroup[$gid] = @() } - $rolesByGroup[$gid] += $label - } - - $groupsWithRoles = $groupIndex.GetEnumerator() | - ForEach-Object { - $gid = $_.Key - $g = $_.Value - $roles = @() - if ($rolesByGroup.ContainsKey($gid)) { - $roles = $rolesByGroup[$gid] | Where-Object { $_ } | Sort-Object -Unique - } - [pscustomobject]@{ - ID = $g.ID - Groupe = $g.Name - RolesCount = $roles.Count - Roles = ($roles -join ', ') - } - } | - Sort-Object -Property Groupe -} - -# --- Affichage conditionnel --- -if ($showUsers) { - Write-Host "" - Write-Host "=== ROLES PAR UTILISATEUR (hors 'Tanium Internal*') ===" -ForegroundColor Green - $usersWithRoles | Format-Table -Property ID,Nom,Username,RolesCount,Roles -AutoSize -} -if ($showGroups) { - Write-Host "" - Write-Host "=== ROLES PAR GROUPE ===" -ForegroundColor Green - $groupsWithRoles | Format-Table -Property ID,Groupe,RolesCount,Roles -AutoSize -} - -# --- Sortie exploitable (ne s’affiche que si tu ne l’assignes pas) --- -[pscustomobject]@{ - UsersWithRoles = $usersWithRoles - GroupsWithRoles = $groupsWithRoles -} diff --git a/API/RBAC_ListUserAndGroup_details_Redden-TanREST.ps1 b/API/RBAC_ListUserAndGroup_details_Redden-TanREST.ps1 deleted file mode 100644 index a438ffa..0000000 --- a/API/RBAC_ListUserAndGroup_details_Redden-TanREST.ps1 +++ /dev/null @@ -1,82 +0,0 @@ -#requires -Version 7.0 -<# -.SYNOPSIS -List Tanium Deploy Software Packages using Get-DeploySoftware. -Reads URL/token from config.json, initializes the session, then queries by: - - All | ByName | ByID | ByVendor | ByCommand | NameRegex -and displays results in Out-GridView (fallback to console table). -#> - -# ========================= -# Block 1 - Prerequisites -# ========================= -$ErrorActionPreference = 'Stop' -try { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 } catch {} -Import-Module Redden-TanREST -Force - -# ========================= -# Block 2 - Load config & init session -# ========================= -$configPath = Join-Path $PSScriptRoot 'config.json' -$TempXml = Join-Path $env:TEMP 'tanium-session-tmp.apicred' - -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 -$TaniumToken = $config.TaniumApiToken - -if ([string]::IsNullOrWhiteSpace($TaniumUrl) -or [string]::IsNullOrWhiteSpace($TaniumToken)) { - throw "Both TaniumUrl and TaniumApiToken must be provided (config.json or environment variables)." -} -if ($TaniumUrl -match '^https?://') { - $TaniumUrl = $TaniumUrl -replace '^https?://','' -replace '/+$','' - Write-Host "Normalized TaniumUrl to host: $TaniumUrl" -} - -$ExportObject = @{ - baseURI = $TaniumUrl - token = ($TaniumToken | ConvertTo-SecureString -AsPlainText -Force) -} -$ExportObject | Export-Clixml -Path $TempXml - -Write-Host "Initializing Tanium session..." -Initialize-TaniumSession -PathToXML $TempXml -Write-Host "Tanium session initialized." - -# ========================= -# Block 3 - Queries -# ========================= -#Get-DeploySoftware -All | Out-GridView -#Get-Role -All | Out-GridView -#Get-UserAndGroupDetail - -# -- Out-GridView available? (PS7 tip: Install-Module Microsoft.PowerShell.GraphicalTools) -$hasOGV = [bool](Get-Command Out-GridView -ErrorAction SilentlyContinue) - -Write-Host "Fetching Users..." -ForegroundColor Cyan -$users = Get-User -All | Sort-Object displayName, username -if ($hasOGV) { - $users | Out-GridView -Title "Tanium Users (All)" -Wait -} else { - $users | Format-Table id, displayName, username, email -AutoSize - Write-Host "(Out-GridView not available; showing table output)" -ForegroundColor Yellow -} - -Write-Host "Fetching User Groups..." -ForegroundColor Cyan -$groups = Get-UserGroup -All | Sort-Object name -if ($hasOGV) { - $groups | Out-GridView -Title "Tanium User Groups (All)" -Wait -} else { - $groups | Format-Table id, name, description -AutoSize - Write-Host "(Out-GridView not available; showing table output)" -ForegroundColor Yellow -} - -# ========================= -# Block 5 - Cleanup -# ========================= -if (Test-Path $TempXml) { - Remove-Item $TempXml -Force -ErrorAction SilentlyContinue - Write-Host "Temporary CLIXML removed: $TempXml" -} diff --git a/API/Sensor_List_Rest.ps1 b/API/Sensor_List_Rest.ps1 deleted file mode 100644 index 101ce5d..0000000 --- a/API/Sensor_List_Rest.ps1 +++ /dev/null @@ -1,165 +0,0 @@ -<# -.SYNOPSIS -List Tanium **Sensors** via the REST API, using Url/Token from `config.json` by default. -Shows: Id, Name, Content Set, Category, Parameters?, CacheSeconds (if exposed). -Supports filters by name/content set/category, Out‑GridView, and CSV export. - -.USAGE -# Basic (reads config.json in the same folder) -./List-Sensors.ps1 - -# Filter by name/content set/category (regex), show grid and export CSV -./List-Sensors.ps1 -NameLike '^BIOS' -ContentSetLike 'Deploy' -CategoryLike 'Hardware' -Grid -ExportCsv C:\Temp\sensors.csv - -# Raw JSON -./List-Sensors.ps1 -Raw - -# Override Url/Token explicitly -./List-Sensors.ps1 -Url tanium.pp.dktinfra.io -Token 'token-xxxx' -#> - -param( - [string]$Url, - [string]$Token, - [switch]$SkipCertCheck, - - [string]$NameLike, - [string]$ContentSetLike, - [string]$CategoryLike, - - [switch]$Raw, - [switch]$Grid, - [string]$ExportCsv -) - -$ErrorActionPreference = 'Stop' -try { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 } catch {} - -# ---------- Helpers ---------- -function New-BaseUri([string]$HostLike) { - $h = $HostLike.Trim() - if ($h -match '^https?://') { $h = $h -replace '^https?://','' } - $h = $h.TrimEnd('/') - if ([string]::IsNullOrWhiteSpace($h)) { throw 'TaniumUrl empty after normalization.' } - "https://$h" -} - -# TLS bypass for Windows PowerShell 5.1 -$script:__oldCb = $null -function Enter-InsecureTls { param([switch]$Enable) - if (-not $Enable) { return } - $script:__oldCb = [System.Net.ServicePointManager]::ServerCertificateValidationCallback - $cb = [System.Net.Security.RemoteCertificateValidationCallback]{ param($s,$c,$ch,$e) $true } - [System.Net.ServicePointManager]::ServerCertificateValidationCallback = $cb -} -function Exit-InsecureTls { - if ($script:__oldCb -ne $null) { - [System.Net.ServicePointManager]::ServerCertificateValidationCallback = $script:__oldCb - $script:__oldCb = $null - } -} - -# ---------- Load config if needed ---------- -$BaseDir = if ($PSScriptRoot) { $PSScriptRoot } else { $pwd.Path } -$configPath = Join-Path $BaseDir 'config.json' -if (-not $Url -or -not $Token) { - if (-not (Test-Path $configPath)) { throw "Missing -Url/-Token and config.json not found: $configPath" } - $cfg = Get-Content -Path $configPath -Raw | ConvertFrom-Json - if (-not $Url) { $Url = [string]$cfg.TaniumUrl } - if (-not $Token) { $Token = [string]$cfg.TaniumApiToken } - if (-not $PSBoundParameters.ContainsKey('SkipCertCheck')) { $SkipCertCheck = [bool]$cfg.SkipCertificateCheck } -} - -$Base = New-BaseUri $Url -$Headers = @{ session = $Token; 'Content-Type' = 'application/json' } - -function Invoke-Tanium([string]$Method,[string]$Path,[object]$BodyObj) { - $uri = if ($Path -match '^https?://') { $Path } else { "$Base$Path" } - $body = if ($null -ne $BodyObj) { $BodyObj | ConvertTo-Json -Depth 10 } else { $null } - $ps7 = ($PSVersionTable.PSVersion.Major -ge 7) - if ($ps7 -and $SkipCertCheck) { - return Invoke-RestMethod -SkipCertificateCheck -Method $Method -Uri $uri -Headers $Headers -Body $body - } else { - try { Enter-InsecureTls -Enable:$SkipCertCheck; return Invoke-RestMethod -Method $Method -Uri $uri -Headers $Headers -Body $body } - finally { Exit-InsecureTls } - } -} - -# ---------- Fetch Sensors + Content Sets (for names) ---------- -$resp = Invoke-Tanium GET "/api/v2/sensors" $null -$sensors = if ($resp.data) { $resp.data } elseif ($resp.items) { $resp.items } else { $resp } - -$csResp = Invoke-Tanium GET "/api/v2/content_sets" $null -$contentSets = if ($csResp.data) { $csResp.data } elseif ($csResp.items) { $csResp.items } else { $csResp } -$csById = @{} -foreach ($cs in $contentSets) { if ($cs.id -ne $null) { $csById[$cs.id] = $cs } } - -if ($Raw) { - [pscustomobject]@{ sensors = $sensors; contentSets = $contentSets } | ConvertTo-Json -Depth 14 - return -} - -if (-not $sensors) { Write-Output 'No sensors returned.'; return } - -# ---------- Helpers to read maybe-present fields ---------- -function TryField($obj, $path) { - try { - $val = $obj - foreach ($p in ($path -split '\.')) { - if ($null -eq $val) { return $null } - $pp = $val.PSObject.Properties[$p] - if (-not $pp) { return $null } - $val = $pp.Value - } - return $val - } catch { return $null } -} - -# ---------- Shape output ---------- -$rows = foreach ($s in $sensors) { - $name = TryField $s 'name' - if ($NameLike -and $name -and -not ($name -match $NameLike)) { continue } - - # content set: could be nested or just id - $csName = '' - $csId = TryField $s 'content_set.id' - if ($null -eq $csId) { $csId = TryField $s 'content_set_id' } - if ($null -ne $csId -and $csById.ContainsKey($csId)) { $csName = $csById[$csId].name } - if ($ContentSetLike -and $csName -and -not ($csName -match $ContentSetLike)) { continue } - - $category = TryField $s 'category' - if ($CategoryLike -and $category -and -not ($category -match $CategoryLike)) { continue } - - $hasParams = $false - if (TryField $s 'parameters') { $hasParams = $true } - elseif (TryField $s 'parameter_definitions') { $hasParams = $true } - elseif (TryField $s 'parameterDefinitions') { $hasParams = $true } - - $cacheSec = TryField $s 'expiration_seconds' - if ($null -eq $cacheSec) { $cacheSec = TryField $s 'cache_seconds' } - - [pscustomobject]@{ - Id = TryField $s 'id' - Name = $name - ContentSet = $csName - Category = $category - Parameters = $hasParams - CacheSeconds = $cacheSec - } -} - -if (-not $rows) { Write-Output 'No matching sensors.'; return } -$rowsSorted = $rows | Sort-Object Name - -if ($ExportCsv) { - try { $rowsSorted | Export-Csv -NoTypeInformation -Encoding UTF8 -Path $ExportCsv; Write-Host "Exported to: $ExportCsv" -ForegroundColor Green } - catch { Write-Warning "CSV export failed: $($_.Exception.Message)" } -} - -if ($Grid) { - $title = "Sensors — {0} item(s)" -f ($rowsSorted.Count) - if (Get-Command Out-GridView -ErrorAction SilentlyContinue) { $rowsSorted | Out-GridView -Title $title; return } - else { Write-Warning "Out-GridView not available. On PS7+: Install-Module Microsoft.PowerShell.GraphicalTools" } -} - -$rowsSorted | Format-Table -AutoSize diff --git a/API/graphql - CheckBiosVersion.ps1 b/API/graphql - CheckBiosVersion.ps1 deleted file mode 100644 index 16ee531..0000000 --- a/API/graphql - CheckBiosVersion.ps1 +++ /dev/null @@ -1,237 +0,0 @@ -<# -.SYNOPSIS -Query Tanium Gateway (GraphQL) for endpoints and return Computer Name (NetBIOS), Model, and BIOS Version. -Supports pagination, optional filtering from a simple list file (one name per line), Out-GridView, and CSV export. - -.DESCRIPTION -- Uses GraphQL operation exampleGetEndpoints with sensors "Model" and "BIOS Version". -- Paginates using pageInfo.hasNextPage / endCursor until all endpoints are collected. -- Optional filtering: provide -ListFile with one computer name per line (NetBIOS or FQDN). -- Normalizes names by taking the part before the first dot and uppercasing (so NetBIOS and FQDN match). -- Reads URL/token from a local config.json if not passed as parameters. -- Optional TLS bypass for lab (-SkipCertCheck or via config.json flag). - -.USAGE -# With config.json (same folder): { "TaniumUrl": "tanium.pp.dktinfra.io", "TaniumApiToken": "token-xxxx", "SkipCertificateCheck": true } -./APICheckBiosVersion.ps1 -Count 200 -Time 30 -MaxAge 900 -PageSize 200 - -# Filter from a list (one name per line, no header) -./APICheckBiosVersion.ps1 -ListFile .\machines.txt - -# Grid view and CSV export -./APICheckBiosVersion.ps1 -ListFile .\machines.txt -Grid -ExportCsv C:\Temp\bios.csv - -# Raw JSON of aggregated edges -./APICheckBiosVersion.ps1 -Raw - -.PARAMETERS --Url, -Token Override Tanium URL and API token (otherwise read from config.json). --Count, -Time, -MaxAge GraphQL collection knobs (expectedCount, stableWaitTime, maxAge seconds). --PageSize Page size for pagination (GraphQL 'first'). --ListFile Optional path to a simple list (one hostname per line) to filter results. --Raw Output aggregated JSON instead of table/grid. --Grid Show results in Out-GridView (if available). --Pick With -Grid, allow selection and output only the selection. --ExportCsv Path to write CSV export. --SkipCertCheck Ignore TLS cert validation (lab/dev only). - -.NOTES -Requires: PowerShell 5.1+ (Out-GridView on PS7 via Microsoft.PowerShell.GraphicalTools). -#> - -param( - [string]$Url, - [string]$Token, - [switch]$SkipCertCheck, - - [int]$Count = 200, - [int]$Time = 30, - [int]$MaxAge = 900, - [int]$PageSize = 200, - - [string]$ListFile, - [switch]$Raw, - [switch]$Grid, - [switch]$Pick, - [string]$ExportCsv -) - -$ErrorActionPreference = 'Stop' -try { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 } catch {} - -# ---------- Helpers ---------- -function Get-GatewayUri { - param([Parameter(Mandatory)][string]$HostLike) - $h = $HostLike.Trim() - if ($h -match '^https?://') { $h = $h -replace '^https?://','' } - $h = $h.TrimEnd('/') - if ([string]::IsNullOrWhiteSpace($h)) { throw 'TaniumUrl empty after normalization.' } - "https://$h/plugin/products/gateway/graphql" -} - -# TLS bypass for Windows PowerShell 5.1 (temporary, restored after call) -$script:__oldCb = $null -function Enter-InsecureTls { param([switch]$Enable) - if (-not $Enable) { return } - $script:__oldCb = [System.Net.ServicePointManager]::ServerCertificateValidationCallback - $cb = [System.Net.Security.RemoteCertificateValidationCallback]{ param($s,$c,$ch,$e) $true } - [System.Net.ServicePointManager]::ServerCertificateValidationCallback = $cb -} -function Exit-InsecureTls { - if ($script:__oldCb -ne $null) { - [System.Net.ServicePointManager]::ServerCertificateValidationCallback = $script:__oldCb - $script:__oldCb = $null - } -} - -function Get-HostKey { - param([string]$Name) - if ([string]::IsNullOrWhiteSpace($Name)) { return '' } - $n = $Name.Trim() - $nb = ($n -split '\.', 2)[0] # take part before first dot if FQDN - return $nb.ToUpperInvariant() -} - -function Read-TargetsFromFile { - param([Parameter(Mandatory)][string]$Path) - if (-not (Test-Path -LiteralPath $Path)) { throw "List file not found: $Path" } - $set = New-Object System.Collections.Generic.HashSet[string] - Get-Content -LiteralPath $Path -Encoding UTF8 | ForEach-Object { - $line = $_.Trim() - if (-not [string]::IsNullOrWhiteSpace($line)) { [void]$set.Add((Get-HostKey $line)) } - } - if ($set.Count -eq 0) { throw "List file is empty: $Path" } - return $set -} - -function Get-ValuesForSensor { - param([array]$Columns, [string]$SensorName) - $match = $Columns | Where-Object { $_.sensor.name -eq $SensorName } - if (-not $match) { return '' } - $vals = @() - foreach ($c in $match) { - foreach ($v in $c.values) { - if ($null -ne $v -and ("$v").Trim()) { $vals += ("$v") } - } - } - # de-dup while preserving order - $uniq = @() - foreach ($v in $vals) { if (-not $uniq.Contains($v)) { $uniq += $v } } - return ($uniq -join ' | ') -} - -# ---------- Load config if needed ---------- -$BaseDir = if ($PSScriptRoot) { $PSScriptRoot } else { $pwd.Path } -$configPath = Join-Path $BaseDir 'config.json' -if (-not $Url -or -not $Token) { - if (-not (Test-Path $configPath)) { throw "Missing -Url/-Token and config.json not found: $configPath" } - $cfg = Get-Content -Path $configPath -Raw | ConvertFrom-Json - if (-not $Url) { $Url = [string]$cfg.TaniumUrl } - if (-not $Token) { $Token = [string]$cfg.TaniumApiToken } - if (-not $PSBoundParameters.ContainsKey('SkipCertCheck')) { $SkipCertCheck = [bool]$cfg.SkipCertificateCheck } -} - -# ---------- Prepare ---------- -$gateway = Get-GatewayUri -HostLike $Url -$headers = @{ 'Content-Type' = 'application/json'; session = $Token } -$targetSet = $null -if ($ListFile) { $targetSet = Read-TargetsFromFile -Path $ListFile } - -# ---------- GraphQL (paginated) ---------- -$Query = @' -query exampleGetEndpoints($count: Int, $time: Int, $maxAge: Int, $first: Int, $after: Cursor) { - endpoints(source: { ts: { expectedCount: $count, stableWaitTime: $time, maxAge: $maxAge } }, first: $first, after: $after) { - edges { node { - computerID - name - serialNumber - ipAddress - sensorReadings(sensors: [{name: "Model"}, {name: "BIOS Version"}]) { - columns { name values sensor { name } } - } - }} - pageInfo { hasNextPage endCursor } - } -} -'@ - -$allEdges = New-Object System.Collections.Generic.List[object] -$cursor = $null - -while ($true) { - $variables = @{ count = $Count; time = $Time; maxAge = $MaxAge; first = $PageSize; after = $cursor } - $bodyObj = @{ query = $Query; variables = $variables; operationName = 'exampleGetEndpoints' } - $bodyJson = $bodyObj | ConvertTo-Json -Depth 12 - - $resp = $null - $ps7 = ($PSVersionTable.PSVersion.Major -ge 7) - if ($ps7 -and $SkipCertCheck) { - $resp = Invoke-RestMethod -SkipCertificateCheck -Method Post -Uri $gateway -Headers $headers -ContentType 'application/json' -Body $bodyJson - } - else { - try { Enter-InsecureTls -Enable:$SkipCertCheck - $resp = Invoke-RestMethod -Method Post -Uri $gateway -Headers $headers -ContentType 'application/json' -Body $bodyJson - } - finally { Exit-InsecureTls } - } - - if ($resp.errors) { throw ("GraphQL errors: " + (($resp.errors | ForEach-Object { $_.message }) -join '; ')) } - - $edges = $resp.data.endpoints.edges - if ($edges) { $allEdges.AddRange($edges) } - - $pi = $resp.data.endpoints.pageInfo - if (-not $pi -or -not $pi.hasNextPage) { break } - $cursor = $pi.endCursor -} - -if ($Raw) { - [pscustomobject]@{ total = $allEdges.Count; edges = $allEdges } | ConvertTo-Json -Depth 14 - return -} - -if ($allEdges.Count -eq 0) { Write-Output 'Aucun endpoint retourné.'; return } - -# ---------- Filter (optional) + Output ---------- -$rows = foreach ($edge in $allEdges) { - $n = $edge.node - $nb = Get-HostKey $n.name - if ($targetSet -and -not $targetSet.Contains($nb)) { continue } - $cols = $n.sensorReadings.columns - [pscustomobject]@{ - Nom = $nb - Modèle = (Get-ValuesForSensor -Columns $cols -SensorName 'Model') - VersionBIOS = (Get-ValuesForSensor -Columns $cols -SensorName 'BIOS Version') - } -} - -if (-not $rows) { Write-Output 'Aucun poste correspondant.'; return } -$rowsSorted = $rows | Sort-Object Nom - -# Optional CSV export -if ($ExportCsv) { - try { - $rowsSorted | Export-Csv -NoTypeInformation -Encoding UTF8 -Path $ExportCsv - Write-Host "Exported to: $ExportCsv" -ForegroundColor Green - } catch { Write-Warning "CSV export failed: $($_.Exception.Message)" } -} - -# Grid mode -if ($Grid) { - $title = "BIOS Versions — {0} poste(s)" -f ($rowsSorted.Count) - if (Get-Command Out-GridView -ErrorAction SilentlyContinue) { - if ($Pick) { - $sel = $rowsSorted | Out-GridView -Title $title -PassThru - if ($sel) { $sel | Format-Table -AutoSize } - return - } else { - $rowsSorted | Out-GridView -Title $title - return - } - } else { - Write-Warning "Out-GridView n'est pas disponible. Sous PowerShell 7+, installe: Install-Module Microsoft.PowerShell.GraphicalTools" - } -} - -# Default console table -$rowsSorted | Format-Table -AutoSize diff --git a/API/graphql - EnvironmentVariable.ps1 b/API/graphql - EnvironmentVariable.ps1 deleted file mode 100644 index 953cca2..0000000 --- a/API/graphql - EnvironmentVariable.ps1 +++ /dev/null @@ -1,119 +0,0 @@ -<# -.SYNOPSIS -Read URL/token from config.json, authenticate to Tanium Gateway (GraphQL), -then query "System Environment Variables" and print selected variables. -#> - -# ========================= -# Block 1 - Load config & build auth -# ========================= -$ErrorActionPreference = 'Stop' - -# config.json is next to this script -$configPath = Join-Path $PSScriptRoot 'config.json' -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 -$TaniumToken = $config.TaniumApiToken - -if ([string]::IsNullOrWhiteSpace($TaniumUrl) -or [string]::IsNullOrWhiteSpace($TaniumToken)) { - throw "Both TaniumUrl and TaniumApiToken must be provided (config.json or environment variables)." -} - -# Normalize host (no scheme/trailing slash) -if ($TaniumUrl -match '^https?://') { $TaniumUrl = $TaniumUrl -replace '^https?://','' -replace '/+$','' } - -# Gateway GraphQL endpoint -$uri = "https://$TaniumUrl/plugin/products/gateway/graphql" - -# HTTP headers with session token -$headers = @{ - "Content-Type" = "application/json" - "session" = $TaniumToken -} - -# ========================= -# Block 2 - Quick auth check (GraphQL ping) -# ========================= -try { - $pingBody = @{ query = 'query { __typename }' } | ConvertTo-Json - $pingResp = Invoke-RestMethod -Uri $uri -Method Post -Headers $headers -Body $pingBody - if ($pingResp.errors) { - $msg = ($pingResp.errors | ForEach-Object { $_.message }) -join '; ' - throw "GraphQL ping returned errors: $msg" - } - Write-Host "Authentication OK (Gateway reachable)." -} -catch { - throw "Authentication or connectivity failed: $($_.Exception.Message)" -} - -# ========================= -# Block 3 - Actual query -# ========================= -# GraphQL variables -$variables = @{ - count = 1 # adjust as needed - time = 10 - maxAge = 600 -} - -# GraphQL query (columns/values only — no 'rows') -$query = @' -query getEndpoints($count: Int, $time: Int, $maxAge: Int) { - endpoints(source: { ts: { expectedCount: $count, stableWaitTime: $time, maxAge: $maxAge }}) { - edges { - node { - computerID - name - serialNumber - ipAddress - sensorReadings(sensors: [{ name: "System Environment Variables" }]) { - columns { - name - values - sensor { name } - } - } - } - } - } -} -'@ - -# Build request body -$body = @{ query = $query; variables = $variables } | ConvertTo-Json -Depth 20 - -# Call Gateway -$response = Invoke-RestMethod -Uri $uri -Method Post -Headers $headers -Body $body -if ($response.errors) { - $msg = ($response.errors | ForEach-Object { $_.message }) -join '; ' - throw "GraphQL returned errors: $msg" -} - -# ========================= -# Block 4 - Parse & print -# ========================= -$endpoints = $response.data.endpoints.edges | ForEach-Object { $_.node } - -# Env vars to keep (case-sensitive per your example) -$varsToKeep = @("PROCESSOR_LEVEL", "windir", "PROCESSOR_REVISION") - -foreach ($endpoint in $endpoints) { - Write-Host "`n$($endpoint.name) [$($endpoint.ipAddress)] $($endpoint.serialNumber) :" - foreach ($reading in $endpoint.sensorReadings) { - foreach ($col in $reading.columns) { - foreach ($env in ($col.values | Where-Object { $_ })) { - if ($env -match "^(.*?)=(.*)$") { - $name = $matches[1] - $value = $matches[2] - if ($varsToKeep -contains $name) { - Write-Host " $name = $value" - } - } - } - } - } -} diff --git a/API/graphql - ListComputerGroup.ps1 b/API/graphql - ListComputerGroup.ps1 deleted file mode 100644 index 56d8011..0000000 --- a/API/graphql - ListComputerGroup.ps1 +++ /dev/null @@ -1,219 +0,0 @@ -# List-ComputerGroups.ps1 — robust fallback + HTTP 400 handling + introspection - -param( - [string]$Url, - [string]$Token, - [switch]$SkipCertCheck, - [int]$PageSize = 200, - [string]$NameLike, - [switch]$Raw, - [switch]$Grid, - [string]$ExportCsv, - [switch]$Introspect -) - -$ErrorActionPreference = 'Stop' -try { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 } catch {} - -function Get-GatewayUri { - param([Parameter(Mandatory)][string]$HostLike) - $h = $HostLike.Trim() - if ($h -match '^https?://') { $h = $h -replace '^https?://','' } - $h = $h.TrimEnd('/') - if ([string]::IsNullOrWhiteSpace($h)) { throw 'TaniumUrl empty after normalization.' } - "https://$h/plugin/products/gateway/graphql" -} - -# TLS bypass for Windows PowerShell 5.1 -$script:__oldCb = $null -function Enter-InsecureTls { param([switch]$Enable) - if (-not $Enable) { return } - $script:__oldCb = [System.Net.ServicePointManager]::ServerCertificateValidationCallback - $cb = [System.Net.Security.RemoteCertificateValidationCallback]{ param($s,$c,$ch,$e) $true } - [System.Net.ServicePointManager]::ServerCertificateValidationCallback = $cb -} -function Exit-InsecureTls { - if ($script:__oldCb -ne $null) { - [System.Net.ServicePointManager]::ServerCertificateValidationCallback = $script:__oldCb - $script:__oldCb = $null - } -} - -# Load config if needed -$BaseDir = if ($PSScriptRoot) { $PSScriptRoot } else { $pwd.Path } -$configPath = Join-Path $BaseDir 'config.json' -if (-not $Url -or -not $Token) { - if (-not (Test-Path $configPath)) { throw "Missing -Url/-Token and config.json not found: $configPath" } - $cfg = Get-Content -Path $configPath -Raw | ConvertFrom-Json - if (-not $Url) { $Url = [string]$cfg.TaniumUrl } - if (-not $Token) { $Token = [string]$cfg.TaniumApiToken } - if (-not $PSBoundParameters.ContainsKey('SkipCertCheck')) { $SkipCertCheck = [bool]$cfg.SkipCertificateCheck } -} - -$gateway = Get-GatewayUri -HostLike $Url -$headers = @{ 'Content-Type' = 'application/json'; session = $Token } - -# ---- Introspection (optional) -if ($Introspect) { -$IntrospectQuery = @' -query { - __type(name: "ComputerGroup") { - name - fields { name type { kind name ofType { kind name } } } - } -} -'@ - $body = @{ query = $IntrospectQuery } | ConvertTo-Json -Depth 6 - $resp = $null - $ps7 = ($PSVersionTable.PSVersion.Major -ge 7) - if ($ps7 -and $SkipCertCheck) { - $resp = Invoke-RestMethod -SkipCertificateCheck -Method Post -Uri $gateway -Headers $headers -Body $body - } else { - try { Enter-InsecureTls -Enable:$SkipCertCheck; $resp = Invoke-RestMethod -Method Post -Uri $gateway -Headers $headers -Body $body } - finally { Exit-InsecureTls } - } - if ($resp.errors) { Write-Error (($resp.errors | ForEach-Object message) -join '; '); return } - $resp.data.__type.fields | Select-Object name,@{n='type';e={$_.type.name ?? $_.type.ofType.name}} | Format-Table -AutoSize - return -} - -# ---- Queries (order = safest → richer) -$Q_Basic = @' -query listComputerGroups($first: Int, $after: Cursor) { - computerGroups(first: $first, after: $after) { - edges { node { id name managementRightsEnabled } } - pageInfo { hasNextPage endCursor } - } -} -'@ - -$Q_ContentSet = @' -query listComputerGroups($first: Int, $after: Cursor) { - computerGroups(first: $first, after: $after) { - edges { node { id name managementRightsEnabled contentSet { name } } } - pageInfo { hasNextPage endCursor } - } -} -'@ - -$Q_ContentSetV2 = @' -query listComputerGroups($first: Int, $after: Cursor) { - computerGroups(first: $first, after: $after) { - edges { node { id name managementRightsEnabled contentSetV2 { name } } } - pageInfo { hasNextPage endCursor } - } -} -'@ - -$Q_Filter = @' -query listComputerGroups($first: Int, $after: Cursor) { - computerGroups(first: $first, after: $after) { - edges { node { - id name managementRightsEnabled - filter { memberOf { name } sensor { name } op value } - } } - pageInfo { hasNextPage endCursor } - } -} -'@ - -$queries = @($Q_Basic, $Q_ContentSet, $Q_ContentSetV2, $Q_Filter) - -function Invoke-Gql { - param([string]$Query, [hashtable]$Vars, [string]$OpName) - $body = @{ query = $Query; variables = $Vars; operationName = $OpName } | ConvertTo-Json -Depth 10 - $ps7 = ($PSVersionTable.PSVersion.Major -ge 7) - try { - if ($ps7 -and $SkipCertCheck) { - return Invoke-RestMethod -SkipCertificateCheck -Method Post -Uri $gateway -Headers $headers -ContentType 'application/json' -Body $body - } else { - Enter-InsecureTls -Enable:$SkipCertCheck - return Invoke-RestMethod -Method Post -Uri $gateway -Headers $headers -ContentType 'application/json' -Body $body - } - } - catch { - # If server returned HTTP 400 with a JSON GraphQL error, parse it and return so we can fallback. - $we = $_.Exception - if ($we.Response) { - try { - $sr = New-Object IO.StreamReader($we.Response.GetResponseStream()) - $txt = $sr.ReadToEnd() - if ($txt) { return ($txt | ConvertFrom-Json) } - } catch { } - } - throw # non-GraphQL error -> bubble up - } - finally { Exit-InsecureTls } -} - -# ---- Fetch with fallback chain -$allEdges = New-Object System.Collections.Generic.List[object] -$cursor = $null -$qIndex = 0 -$opName = 'listComputerGroups' - -while ($true) { - $vars = @{ first = $PageSize; after = $cursor } - $resp = Invoke-Gql -Query $queries[$qIndex] -Vars $vars -OpName $opName - - if ($resp.errors) { - if ($qIndex -lt ($queries.Count - 1)) { - # restart from page 1 with next query - $qIndex++; $cursor = $null; $allEdges.Clear() - continue - } else { - throw ("GraphQL errors: " + (($resp.errors | ForEach-Object { $_.message }) -join '; ')) - } - } - - $edges = $resp.data.computerGroups.edges - if ($edges) { $allEdges.AddRange($edges) } - - $pi = $resp.data.computerGroups.pageInfo - if (-not $pi -or -not $pi.hasNextPage) { break } - $cursor = $pi.endCursor -} - -if ($Raw) { [pscustomobject]@{ total = $allEdges.Count; edges = $allEdges } | ConvertTo-Json -Depth 14; return } -if ($allEdges.Count -eq 0) { Write-Output 'No computer groups returned.'; return } - -function Get-ContentSetName($n) { - if ($n.PSObject.Properties.Match('contentSet').Count -gt 0 -and $n.contentSet) { return $n.contentSet.name } - if ($n.PSObject.Properties.Match('contentSetV2').Count -gt 0 -and $n.contentSetV2) { return $n.contentSetV2.name } - return '' -} -function Get-FilterSummary($n) { - if (-not $n.PSObject.Properties.Match('filter')) { return '' } - $f = $n.filter; if ($null -eq $f) { return '' } - if ($f.memberOf -and $f.memberOf.name) { return ("memberOf: " + $f.memberOf.name) } - if ($f.sensor -and $f.sensor.name) { return ("sensor '" + $f.sensor.name + "' " + $f.op + " '" + $f.value + "'") } - return '' -} - -$rows = foreach ($edge in $allEdges) { - $n = $edge.node - if ($NameLike -and -not ($n.name -match $NameLike)) { continue } - [pscustomobject]@{ - Id = $n.id - Name = $n.name - ManagementRights = $n.managementRightsEnabled - ContentSet = (Get-ContentSetName $n) - Filter = (Get-FilterSummary $n) - } -} - -if (-not $rows) { Write-Output 'No matching groups.'; return } -$rowsSorted = $rows | Sort-Object Name - -if ($ExportCsv) { - try { $rowsSorted | Export-Csv -NoTypeInformation -Encoding UTF8 -Path $ExportCsv; Write-Host "Exported to: $ExportCsv" -ForegroundColor Green } - catch { Write-Warning "CSV export failed: $($_.Exception.Message)" } -} - -if ($Grid) { - $title = "Computer Groups — {0} item(s)" -f ($rowsSorted.Count) - if (Get-Command Out-GridView -ErrorAction SilentlyContinue) { $rowsSorted | Out-GridView -Title $title; return } - else { Write-Warning "Out-GridView not available. On PS7+: Install-Module Microsoft.PowerShell.GraphicalTools" } -} - -$rowsSorted | Format-Table -AutoSize diff --git a/API/rest - list sensor detail.ps1 b/API/rest - list sensor detail.ps1 deleted file mode 100644 index 35dfe46..0000000 --- a/API/rest - list sensor detail.ps1 +++ /dev/null @@ -1,238 +0,0 @@ -<# -.SYNOPSIS -Export or print the scripts used by Sensors per OS (Windows/Mac/Linux/AIX/Solaris…), via Tanium REST. -Reads Url/Token from config.json. Can dump files (-DumpPath) and/or print scripts to console (-Print). - -.USAGE -# Index only (table) -.\Export-SensorScriptsByOS.ps1 - -# Dump all scripts to files + show a grid -.\Export-SensorScriptsByOS.ps1 -DumpPath .\out -Grid - -# Only Windows scripts of sensors matching a name regex, and print to console -.\Export-SensorScriptsByOS.ps1 -NameLike '^WSUS|BIOS' -Os Windows -Print - -# One sensor by id, dump to folder and print -.\Export-SensorScriptsByOS.ps1 -Id 665 -DumpPath C:\Temp\sensor_src -Print - -# Export index to CSV -.\Export-SensorScriptsByOS.ps1 -DumpPath .\out -ExportCsv .\index.csv -#> - -param( - [string]$Url, - [string]$Token, - [switch]$SkipCertCheck, - - [string]$NameLike, - [int]$Id, - - [string[]]$Os, # ex: -Os Windows,Mac - [switch]$Print, # print script text in console - [string]$DumpPath, # write each script to a file - [string]$ExportCsv, # write index CSV - - [switch]$Grid, - [switch]$Raw -) - -$ErrorActionPreference = 'Stop' -try { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 } catch {} - -# ---------- Helpers ---------- -function New-BaseUri([string]$HostLike) { - $h = $HostLike.Trim() - if ($h -match '^https?://') { $h = $h -replace '^https?://','' } - $h = $h.TrimEnd('/') - if ([string]::IsNullOrWhiteSpace($h)) { throw 'TaniumUrl empty after normalization.' } - "https://$h" -} - -# TLS bypass for Windows PowerShell 5.1 -$script:__oldCb = $null -function Enter-InsecureTls { param([switch]$Enable) - if (-not $Enable) { return } - $script:__oldCb = [System.Net.ServicePointManager]::ServerCertificateValidationCallback - $cb = [System.Net.Security.RemoteCertificateValidationCallback]{ param($s,$c,$ch,$e) $true } - [System.Net.ServicePointManager]::ServerCertificateValidationCallback = $cb -} -function Exit-InsecureTls { - if ($script:__oldCb -ne $null) { - [System.Net.ServicePointManager]::ServerCertificateValidationCallback = $script:__oldCb - $script:__oldCb = $null - } -} - -# ---------- Load config ---------- -$BaseDir = if ($PSScriptRoot) { $PSScriptRoot } else { $pwd.Path } -$configPath = Join-Path $BaseDir 'config.json' -if (-not $Url -or -not $Token) { - if (-not (Test-Path $configPath)) { throw "Missing -Url/-Token and config.json not found: $configPath" } - $cfg = Get-Content -Path $configPath -Raw | ConvertFrom-Json - if (-not $Url) { $Url = [string]$cfg.TaniumUrl } - if (-not $Token) { $Token = [string]$cfg.TaniumApiToken } - if (-not $PSBoundParameters.ContainsKey('SkipCertCheck')) { $SkipCertCheck = [bool]$cfg.SkipCertificateCheck } -} - -$Base = New-BaseUri $Url -$Headers = @{ session = $Token; 'Content-Type' = 'application/json' } - -function Invoke-Tanium([string]$Method,[string]$Path,[object]$BodyObj,[switch]$AllowError) { - $uri = if ($Path -match '^https?://') { $Path } else { "$Base$Path" } - $body = if ($null -ne $BodyObj) { $BodyObj | ConvertTo-Json -Depth 12 } else { $null } - $ps7 = ($PSVersionTable.PSVersion.Major -ge 7) - try { - if ($ps7 -and $SkipCertCheck) { - return Invoke-RestMethod -SkipCertificateCheck -Method $Method -Uri $uri -Headers $Headers -Body $body - } else { - Enter-InsecureTls -Enable:$SkipCertCheck - return Invoke-RestMethod -Method $Method -Uri $uri -Headers $Headers -Body $body - } - } - catch { if ($AllowError) { return $null } else { throw } } - finally { Exit-InsecureTls } -} - -function TryGet($obj, [string[]]$names) { - foreach ($n in $names) { - $p = $obj.PSObject.Properties[$n] - if ($p -and $p.Value) { return $p.Value } - } - return $null -} -function CleanName([string]$s) { if ($s) { ($s -replace '[\\/:*?"<>|]','_').Trim() } } -function Detect-OS([string]$raw) { - if (-not $raw) { return $null } - $r = $raw.ToLowerInvariant() - if ($r -match 'win') { return 'Windows' } - if ($r -match 'mac|darwin|osx'){ return 'Mac' } - if ($r -match 'lin|posix|unix'){ return 'Linux' } - # laissons tels quels pour AIX/Solaris/HP-UX/etc. - return ($raw -replace '\s+',' ').Trim() -} - -# Per-OS extraction from a detailed sensor payload -function Get-SourcesByOS([object]$sensorDetail) { - $map = @{} - # 1) flat fields - $ws = TryGet $sensorDetail @('windows_source','windowsQuery','windows_query') - $ls = TryGet $sensorDetail @('linux_source','posix_source','linuxQuery','linux_query','posixQuery','posix_query','solaris_source','aix_source') - $ms = TryGet $sensorDetail @('mac_source','darwin_source','macQuery','mac_query') - $generic = TryGet $sensorDetail @('source','query_text','script','definition','definition_text','content') - if ($ws) { $map['Windows'] = [string]$ws } - if ($ms) { $map['Mac'] = [string]$ms } - if ($ls) { $map['Linux'] = [string]$ls } # certaines versions renvoient aussi AIX/Solaris en champs dédiés : traités ci-dessous - - # 2) nested arrays, avec platform/operating_system + source/text/... - foreach ($arrName in @('queries','sources','os_queries','platforms')) { - $arr = $sensorDetail.PSObject.Properties[$arrName].Value - if ($arr -and ($arr -is [System.Collections.IEnumerable])) { - foreach ($q in $arr) { - $plat = TryGet $q @('platform','operating_system','os','name','type') - $code = TryGet $q @('source','text','query_text','script','definition','content','body') - if ($code) { - $os = Detect-OS ([string]$plat) - if (-not $os) { $os = 'All' } - # Ne pas écraser si déjà présent - if (-not $map.ContainsKey($os)) { $map[$os] = [string]$code } - } - } - } - } - if ($map.Count -eq 0 -and $generic) { $map['All'] = [string]$generic } - return $map -} - -# ---------- Get sensor list (or just one) ---------- -$items = $null -if ($Id) { - $d = Invoke-Tanium GET "/api/v2/sensors/$Id" $null -AllowError - if ($Raw) { $d | ConvertTo-Json -Depth 14; return } - $list = Invoke-Tanium GET "/api/v2/sensors" $null - $items = if ($list.data) { $list.data } elseif ($list.items) { $list.items } else { $list } - $items = $items | Where-Object { $_.id -eq $Id } -} else { - $list = Invoke-Tanium GET "/api/v2/sensors" $null - $items = if ($list.data) { $list.data } elseif ($list.items) { $list.items } else { $list } -} - -if (-not $items) { Write-Output 'No sensors visible via API.'; return } -if ($NameLike) { $items = $items | Where-Object { $_.name -match $NameLike } } -if (-not $items) { Write-Output 'No matching sensors.'; return } - -# Prepare dump folder if requested -if ($DumpPath) { - if (-not (Test-Path -LiteralPath $DumpPath)) { New-Item -ItemType Directory -Path $DumpPath | Out-Null } -} - -# Normalize OS filter to case-insensitive hashset -$osFilter = $null -if ($Os -and $Os.Count -gt 0) { - $osFilter = New-Object System.Collections.Generic.HashSet[string] ([StringComparer]::OrdinalIgnoreCase) - foreach ($o in $Os) { if ($o) { [void]$osFilter.Add($o) } } -} - -$rows = New-Object System.Collections.Generic.List[object] - -foreach ($s in $items) { - $sid = $s.id; $sname = [string]$s.name - $detail = Invoke-Tanium GET "/api/v2/sensors/$sid" $null -AllowError - # unwrap common envelopes - $sensorDetail = $null - foreach ($k in 'data','sensor','item') { if ($null -eq $sensorDetail -and $detail.PSObject.Properties[$k]) { $sensorDetail = $detail.$k } } - if (-not $sensorDetail) { if ($detail.items -and $detail.items.Count -gt 0) { $sensorDetail = $detail.items[0] } else { $sensorDetail = $detail } } - - $sources = Get-SourcesByOS $sensorDetail - if ($sources.Keys.Count -eq 0) { - $rows.Add([pscustomobject]@{ Id=$sid; Name=$sname; OS='—'; HasScript=$false; Length=0; Path=''; Text=$null }) - continue - } - - # apply OS filter if any - $osKeys = $sources.Keys - if ($osFilter) { $osKeys = $osKeys | Where-Object { $osFilter.Contains($_) } } - - foreach ($os in $osKeys) { - $txt = [string]$sources[$os] - $len = ($txt | Measure-Object -Character).Characters - $outPath = '' - if ($DumpPath) { - $fn = (CleanName($sname) + "__" + ($os -replace '\s+','_') + ".txt") - $outPath = Join-Path $DumpPath $fn - Set-Content -LiteralPath $outPath -Value $txt -Encoding UTF8 - } - $rows.Add([pscustomobject]@{ Id=$sid; Name=$sname; OS=$os; HasScript=$true; Length=$len; Path=$outPath; Text=$txt }) - } -} - -$rows = $rows | Sort-Object Name, OS - -# Optional CSV of the index (no full text) -if ($ExportCsv) { - try { - $rows | Select-Object Id,Name,OS,HasScript,Length,Path | Export-Csv -NoTypeInformation -Encoding UTF8 -Path $ExportCsv - Write-Host "Index exported to: $ExportCsv" -ForegroundColor Green - } catch { Write-Warning "CSV export failed: $($_.Exception.Message)" } -} - -# Grid -if ($Grid) { - if (Get-Command Out-GridView -ErrorAction SilentlyContinue) { - $rows | Select-Object Id,Name,OS,HasScript,Length,Path | Out-GridView -Title ("Sensor Scripts by OS — {0} rows" -f $rows.Count) - } else { - Write-Warning "Out-GridView not available. On PS7+: Install-Module Microsoft.PowerShell.GraphicalTools" - } -} - -# Table -$rows | Select-Object Id,Name,OS,HasScript,Length,Path | Format-Table -AutoSize - -# Print scripts to console -if ($Print) { - foreach ($r in $rows) { - if (-not $r.HasScript -or -not $r.Text) { continue } - Write-Host "`n===== SENSOR: $($r.Name) | OS: $($r.OS) | Id: $($r.Id) =====" -ForegroundColor Cyan - $r.Text - } -} diff --git a/API/test.ps1 b/API/test.ps1 deleted file mode 100644 index 5ee6b85..0000000 --- a/API/test.ps1 +++ /dev/null @@ -1,89 +0,0 @@ -<# -But : lire les infos endpoints à partir du cache (TDS) via GraphQL (Tanium Gateway) -#> - -# --- Pré-requis : même init que ton script --- -$ErrorActionPreference = 'Stop' -try { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 } catch {} -Import-Module Redden-TanREST -Force - -# Charger config.json + Initialiser la session (identique à ton 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 = if ($config.TaniumUrl) { $config.TaniumUrl } else { $env:TANIUM_URL } -$TaniumApiToken = if ($config.TaniumApiToken) { $config.TaniumApiToken } else { $env:TANIUM_TOKEN } -if ($TaniumUrl -match '^https?://') { $TaniumUrl = $TaniumUrl -replace '^https?://','' -replace '/+$','' } - -$TempXml = Join-Path $env:TEMP 'tanium-session-tmp.apicred' -@{ - baseURI = $TaniumUrl - token = ($TaniumApiToken | ConvertTo-SecureString -AsPlainText -Force) -} | Export-Clixml -Path $TempXml - -Initialize-TaniumSession -PathToXML $TempXml -# (Le point d’accès GraphQL est /plugin/products/gateway/graphql côté Tanium; même auth que REST. :contentReference[oaicite:1]{index=1}) - -# --- Requête GraphQL (TDS/cached) --- -# NB : ici on filtre sur l’OS qui "contient Windows". -# Si le champ diffère dans ton schéma (ex: operatingSystemName), adapte 'path' et/ou les champs retournés. -$query = @' -query ($first:Int, $after:Cursor, $os:String!) { - endpoints( - first: $first - after: $after - # Filtre simple : champ "operatingSystem" qui contient la valeur $os - filter: { path: "operatingSystem", value: $os, op: CONTAINS } - ) { - totalRecords - edges { - node { - id - name - ipAddress - serialNumber - operatingSystem - eidLastSeen - } - } - pageInfo { hasNextPage endCursor } - } -} -'@ - -# Variables initiales (page de 500 éléments) -$variables = @{ - first = 500 - after = $null - os = 'Windows' -} - -# --- Exécution + pagination --- -$all = New-Object System.Collections.Generic.List[object] - -do { - # Invoke-TaniumGateway exécute la requête/variables avec ta session Redden-TanREST. :contentReference[oaicite:2]{index=2} - $out = Invoke-TaniumGateway -Query $query -Variables $variables - - $page = $out.data.endpoints - foreach ($edge in $page.edges) { - $n = $edge.node - $all.Add([pscustomobject]@{ - Id = $n.id - Name = $n.name - IP = $n.ipAddress - Serial = $n.serialNumber - OS = $n.operatingSystem - LastSeen = $n.eidLastSeen - }) - } - - $variables.after = $page.pageInfo.endCursor -} while ($page.pageInfo.hasNextPage) - -# Affichage (Grid) -$all | Out-GridView -Title 'Windows endpoints (TDS cached via GraphQL)' - -# --- Nettoyage --- -Remove-Item $TempXml -Force -ErrorAction SilentlyContinue diff --git a/Interact/Reg-Filter-Even-Numbered-hostnames/readme.md b/Interact/Reg-Filter-Even-Numbered-hostnames/readme.md deleted file mode 100644 index 4c77929..0000000 --- a/Interact/Reg-Filter-Even-Numbered-hostnames/readme.md +++ /dev/null @@ -1,41 +0,0 @@ -# 🔍 Regex Filter for Even-Numbered Hostnames - -This regex is used in **Tanium filters** to match hostnames ending with an **even digit** in their first label. - ---- - -## ✅ Even-Numbered Hostnames (FQDN) - -```regex -^[^.]*[02468]\..+ -``` -^[^.]* → matches the first label (hostname part before the first dot). -[02468] → requires it to end with an even digit. -\..+ → ensures there is a domain suffix (must be a FQDN). - -Examples -- pc100.dkcorp.net ✅ -- pc8.lab.example.org ✅ -- pc101.sud.dkcorp.net ❌ (ends with odd digit 1) -- pc8 ❌ (not a FQDN, no dot) - -## ✅ Even-Numbered Hostnames (Optional FQDN) - -```regex -^[^.]*[02468](?:\..+)?$ -``` -^[^.]* → matches the first label (hostname part before the first dot). -[02468] → requires it to end with an even digit. -(?:\..+)? → optional dot + domain (accepts both hostname and FQDN) - -✅ Examples -Matches: -- pc8 -- pc100 -- pc8.lab -- pc100.dkcorp.net - -❌ Does not match: -- pc101 (ends with odd digit) -- pc8. (nothing after the dot) -- pc.8 (even digit not at the end of first label) diff --git a/Packages/RegistryOnHKLM/DisableWPAD.ps1 b/Packages/RegistryOnHKLM/DisableWPAD.ps1 deleted file mode 100644 index bf27c9f..0000000 --- a/Packages/RegistryOnHKLM/DisableWPAD.ps1 +++ /dev/null @@ -1,22 +0,0 @@ -$ErrorActionPreference = 'Stop' - -$isOS64 = [Environment]::Is64BitOperatingSystem -$isProc64 = [Environment]::Is64BitProcess - -$KeyPS = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\WinHttp' -$KeyRel = 'SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\WinHttp' -$Name = 'DisableWpad' - -if ($isOS64 -and -not $isProc64) { - # 32-bit PowerShell on 64-bit OS -> write to 64-bit registry view - $bk = [Microsoft.Win32.RegistryKey]::OpenBaseKey( - [Microsoft.Win32.RegistryHive]::LocalMachine, - [Microsoft.Win32.RegistryView]::Registry64 - ) - $k = $bk.CreateSubKey($KeyRel) - $k.SetValue($Name, 1, [Microsoft.Win32.RegistryValueKind]::DWord) - $k.Close() -} else { - if (-not (Test-Path -LiteralPath $KeyPS)) { New-Item -Path $KeyPS -Force | Out-Null } - New-ItemProperty -Path $KeyPS -Name $Name -Value 1 -PropertyType DWord -Force | Out-Null -} diff --git a/Packages/RegistryOnHKLM/readme.md b/Packages/RegistryOnHKLM/readme.md deleted file mode 100644 index 22737c5..0000000 --- a/Packages/RegistryOnHKLM/readme.md +++ /dev/null @@ -1,10 +0,0 @@ -# 🧩 HKLM Registry Write (64-bit) - -## 🔧 What it does -- Opens **HKLM** in the **64-bit registry view**. -- Creates/opens subkey -- Sets value - -## ✅ Prerequisites -- Run as **Administrator**. -- Writes to the **64-bit** hive; use `Registry32` if you need the 32-bit view. diff --git a/Packages/shutdown.ps1 b/Packages/shutdown.ps1 deleted file mode 100644 index 2955d15..0000000 --- a/Packages/shutdown.ps1 +++ /dev/null @@ -1,37 +0,0 @@ -#requires -version 5.1 -# Forced shutdown in 30 seconds with on-screen message. -# Works from 32-bit PowerShell on 64-bit Windows. Run as Administrator. - -$Message = 'Shutdown by Tanium' -$TimeoutSeconds = 30 - -# Admin check -$principal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent()) -if (-not $principal.IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)) { - Write-Error 'Run this script as Administrator.' - exit 1 -} - -# Pick correct shutdown.exe (Sysnative when 32-bit PS on 64-bit OS) -function Get-ShutdownExePath { - $sysnative = Join-Path $env:WINDIR 'Sysnative\shutdown.exe' - $system32 = Join-Path $env:WINDIR 'System32\shutdown.exe' - if ([Environment]::Is64BitOperatingSystem -and -not [Environment]::Is64BitProcess -and (Test-Path $sysnative)) { - return $sysnative - } else { - return $system32 - } -} -$exe = Get-ShutdownExePath - -# Optional trace in Event Log -try { - $src = 'Tanium-Shutdown-PS' - if (-not [System.Diagnostics.EventLog]::SourceExists($src)) { - New-EventLog -LogName Application -Source $src -ErrorAction SilentlyContinue - } - Write-EventLog -LogName Application -Source $src -EntryType Information -EventId 10011 -Message $Message -} catch {} - -# Schedule forced shutdown with 30s countdown and message -& $exe /s /f /t $TimeoutSeconds /c $Message diff --git a/Provision/unattend.xml/readme.md b/Provision/unattend.xml/readme.md deleted file mode 100644 index b49596b..0000000 --- a/Provision/unattend.xml/readme.md +++ /dev/null @@ -1,5 +0,0 @@ -# Documentation - -For the full documentation, please visit the link below: - -[Windows Provisionning With Tanium](https://blog.wuibaille.fr/2024/09/windows-provisionning-with-tanium/) diff --git a/Provision/unattend.xml/unattend.xml b/Provision/unattend.xml/unattend.xml deleted file mode 100644 index b15e5f3..0000000 --- a/Provision/unattend.xml/unattend.xml +++ /dev/null @@ -1,114 +0,0 @@ - - - - - true - - - - - - MyWorkgroup - - - - nomPC - MonOrganisation - MonOrganisation - true - Romance Standard Time - M7XTQ-FN8P6-TTKYV-9D4CC-J462D - - - www.google.fr - - - - - EnableAdmin - 1 - cmd /c net user Administrator /active:yes - - - UnfilterAdministratorToken - 2 - cmd /c reg add HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v FilterAdministratorToken /t REG_DWORD /d 0 /f - - - disable user account page - 3 - reg add HKLM\Software\Microsoft\Windows\CurrentVersion\Setup\OOBE /v UnattendCreatedUser /t REG_DWORD /d 1 /f - - - disable async RunOnce - 4 - reg add HKLM\Software\Microsoft\Windows\CurrentVersion\Explorer /v AsyncRunOnce /t REG_DWORD /d 0 /f - - - - - fr-fr;040c:0000040c - en-us - en-us - en-us - - - 0 - - "" - 1 - 9 - 9 - 1 - "" - "" - "" - Default - - - - 1 - - - - - - - Password1 - true</PlainText> - </AdministratorPassword> - </UserAccounts> - <AutoLogon> - <Enabled>true</Enabled> - <Username>Administrator</Username> - <Domain>.</Domain> - <Password> - <Value>Password1</Value> - <PlainText>true</PlainText> - </Password> - <LogonCount>1</LogonCount> - </AutoLogon> - <Display></Display> - <OOBE> - <HideEULAPage>true</HideEULAPage> - <NetworkLocation>Work</NetworkLocation> - <ProtectYourPC>1</ProtectYourPC> - <HideLocalAccountScreen>true</HideLocalAccountScreen> - <HideOnlineAccountScreens>true</HideOnlineAccountScreens> - <HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE> - <SkipMachineOOBE>true</SkipMachineOOBE> - <SkipUserOOBE>true</SkipUserOOBE> - </OOBE> - <RegisteredOrganization>MonOrganisation</RegisteredOrganization> - <RegisteredOwner>MonOrganisation</RegisteredOwner> - <TimeZone>Romance Standard Time</TimeZone> - </component> - <component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <InputLocale>fr-fr;040c:0000040c</InputLocale> - <SystemLocale>en-us</SystemLocale> - <UILanguage>en-us</UILanguage> - <UserLocale>en-us</UserLocale> - </component> - </settings> - <cpi:offlineImage cpi:source="" xmlns:cpi="urn:schemas-microsoft-com:cpi" /> -</unattend>