Public/Convert-IntunePortalCapture.ps1
|
# Auto-generated by module/Build-Module.ps1 from en/scripts/Invoke-IntunePortalCaptureToScript.ps1 # Edit the source script, then re-run Build-Module.ps1. Do not edit this file directly. function Convert-IntunePortalCapture { <# .SYNOPSIS EXPERIMENTAL, OPT-IN: turn a JSON payload captured from the Intune portal (for objects the standard Graph token cannot export — e.g. Device Inventory policies, gated/internal endpoints) into a review-first recreation script, using a configurable AI endpoint. .DESCRIPTION Some Intune features are driven by the portal's internal token and are not returned by a regular Graph app/delegated token. You can still capture the request/response JSON from the browser (F12 → Network) on the SOURCE tenant. Feed that JSON here; the AI drafts a PowerShell + Microsoft Graph recreation script for the TARGET tenant. Output is for HUMAN REVIEW — nothing is executed. AI settings come from config.ps1 (git-ignored) or INTUNE_AI_* environment variables. The API key is YOURS and is never shipped with the kit. .PARAMETER CaptureFile Path to the JSON captured from the portal. .PARAMETER Description Short description of what the JSON is (e.g. "Device Inventory policy / properties catalog"). .PARAMETER OutputPath Where to write the recreation script + notes. Default: .\ai-output\captured .PARAMETER Language Language of the generated notes: en | fr. Default en. .EXAMPLE .\Invoke-IntunePortalCaptureToScript.ps1 -CaptureFile .\device-inventory.json -Description "Device Inventory policy" #> [CmdletBinding()] param( [Parameter(Mandatory)][string]$CaptureFile, [string]$Description = 'captured Intune portal object', [string]$OutputPath = (Join-Path (Get-Location) 'ai-output\captured'), [ValidateSet('en','fr')][string]$Language = 'en' ) $ErrorActionPreference = 'Stop' [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 if (-not (Test-Path -LiteralPath $CaptureFile)) { throw "CaptureFile not found: $CaptureFile" } # --- AI config (config.ps1 at the bundle root, else environment). Key never bundled. --- $cfg = Join-Path (Split-Path -Parent $PSScriptRoot) 'config.ps1' if (Test-Path -LiteralPath $cfg) { . $cfg } $AiProvider = if ($AiProvider) { $AiProvider } elseif ($env:INTUNE_AI_PROVIDER) { $env:INTUNE_AI_PROVIDER } else { 'OpenAI' } $AiEndpoint = if ($AiEndpoint) { $AiEndpoint } else { $env:INTUNE_AI_ENDPOINT } $AiApiKey = if ($AiApiKey) { $AiApiKey } else { $env:INTUNE_AI_API_KEY } $AiModel = if ($AiModel) { $AiModel } else { $env:INTUNE_AI_MODEL } if (-not $AiApiKey) { throw "No AI API key. Set `$AiApiKey (and `$AiEndpoint / `$AiModel / `$AiProvider) in config.ps1 or INTUNE_AI_* env vars." } function Invoke-AiChat { param([string]$System,[string]$User) $body = @{ messages = @(@{ role='system'; content=$System }, @{ role='user'; content=$User }); temperature = 0.2 } switch ($AiProvider) { 'AzureOpenAI' { if (-not $AiEndpoint) { throw 'AzureOpenAI requires $AiEndpoint.' } $resp = Invoke-RestMethod -Method POST -Uri $AiEndpoint -Headers @{ 'api-key' = $AiApiKey } -ContentType 'application/json' -Body ($body | ConvertTo-Json -Depth 12) } 'OpenAI' { $body.model = if ($AiModel) { $AiModel } else { 'gpt-4.1-mini' } $uri = if ($AiEndpoint) { $AiEndpoint } else { 'https://api.openai.com/v1/chat/completions' } $resp = Invoke-RestMethod -Method POST -Uri $uri -Headers @{ Authorization = "Bearer $AiApiKey" } -ContentType 'application/json' -Body ($body | ConvertTo-Json -Depth 12) } default { if (-not $AiEndpoint) { throw 'Custom provider requires $AiEndpoint.' } if ($AiModel) { $body.model = $AiModel } $resp = Invoke-RestMethod -Method POST -Uri $AiEndpoint -Headers @{ Authorization = "Bearer $AiApiKey" } -ContentType 'application/json' -Body ($body | ConvertTo-Json -Depth 12) } } return [string]$resp.choices[0].message.content } $raw = Get-Content -LiteralPath $CaptureFile -Raw # Light redaction of obvious secret-like keys before sending. $raw = [regex]::Replace($raw, '("(?:value|password|secret|token|key|clientSecret)"\s*:\s*)"[^"]*"', '$1"<REDACTED>"', 'IgnoreCase') $system = @" You are a senior Microsoft Intune and Microsoft Graph engineer. You receive a JSON payload captured from the Intune portal for an object that a standard Graph token cannot export ($Description). Write the answer in $Language and produce: a short explanation, then a PowerShell + Microsoft Graph (Invoke-MgGraphRequest, beta) recreation script for the TARGET tenant, using -WhatIf where relevant and <PLACEHOLDER> for anything secret or tenant-specific. If the endpoint is undocumented, say so and give the best-effort portal steps. Return Markdown with a single fenced 'powershell' code block. "@ New-Item -ItemType Directory -Force -Path $OutputPath | Out-Null Write-Host "Asking the AI to draft a recreation script..." -ForegroundColor Cyan $answer = Invoke-AiChat -System $system -User $raw $base = [System.IO.Path]::GetFileNameWithoutExtension($CaptureFile) Set-Content -LiteralPath (Join-Path $OutputPath ("{0}.notes.md" -f $base)) -Value $answer -Encoding UTF8 $m = [regex]::Match($answer, '(?s)```powershell(.*?)```') if ($m.Success) { Set-Content -LiteralPath (Join-Path $OutputPath ("{0}.recreate.ps1" -f $base)) ` -Value ("# REVIEW BEFORE RUNNING - AI-generated from a portal capture. Never run blindly.`n" + $m.Groups[1].Value.Trim()) -Encoding UTF8 } Write-Host ("Output: {0}" -f $OutputPath) -ForegroundColor Green Write-Host "Review everything before running any generated script." -ForegroundColor Yellow } |