Isard.ps1
# https://gitlab.com/isard/isardvdi/-/tree/main/api/src/api/schemas # /api/v3/user # /api/v3/user/config function Connect-Isard { param( [Parameter(Position = 0, HelpMessage = "Nom de la màquina virtual")] [string] $Name ) if (-Not(Get-Command "remote-viewer.exe" -ErrorAction SilentlyContinue)) { Install-Scoop virt-viewer -Bucket "extras" } $vm = Get-Isard -Name $Name -Raw if ($Null -eq $vm) { Write-IsardLog $Name Write-Host -ForegroundColor Red "No existeix cap màquina amb aquest nom" return } # TODO comprovar màquina arrencada if ($vm.state -ne "Started") { Start-Isard $Name -Wait } Write-IsardLog $Name Write-Host "Obtenint el fitxer de configuració ..." -NoNewline $data = Invoke-IsardRequest -Endpoint "/api/v3/desktop/$($vm.id)/viewer/file-spice" Write-Host -ForegroundColor Green " Fet." $data = $data | ConvertFrom-Json $file = Get-IsardPath -Name "isard-spice.vv" $content = $data.content $Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding $False [System.IO.File]::WriteAllLines($file, $content, $Utf8NoBomEncoding) remote-viewer.exe $file } function Get-Isard { param( [Parameter(Position = 0, HelpMessage = "Nom de la màquina virtual")] [string] $Name, [switch] $Raw ) $vms = Invoke-IsardRequest -Endpoint "/api/v3/user/desktops" $vms = $vms | ConvertFrom-Json if ($Name -ne "") { $vms = $vms | Where-Object { $_.name -eq $Name } | Select-Object -First 1 if (($Null -eq $vms) -And -Not($Raw)) { Write-IsardLog $Name Write-Host -ForegroundColor Red "No existeix cap màquina amb aquest nom" return } } if ($Raw) { return $vms } $vms | Sort-Object name | Format-Table -AutoSize -Property @{ Label = "Nom" Expression = { $_.name } }, @{ Label = "Estat" Expression = { $_.state } }, @{ Label = "IP" Expression = { $_.ip } } } function New-Isard { param( [Parameter(Position = 0, Mandatory = $true, HelpMessage = "Nom de la màquina virtual")] [string] $Name, [string] $os = "ubuntu" ) $oss = @("ubuntu","windows") if ($oss -notcontains $os) { Write-Host -ForegroundColor Red "Error" -NoNewline Write-Host ": Els unics sistemes operatius són 'ubuntu' i 'windows'" return } $endpoint = "/api/v3/persistent_desktop" $vm = Get-Isard -Name $Name -Raw if ($vm) { Write-IsardLog $Name Write-Host -ForegroundColor Red "Ja existeix una màquina amb aquest nom" return } $template = $isard_templates[$os] $template.name = $Name Write-IsardLog $Name Write-Host "Creant la màquina ..." -NoNewline $data = Invoke-IsardRequest -Endpoint $endpoint -Data $template Write-Host -ForegroundColor Yellow $data.id -NoNewline Write-Host -ForegroundColor Green " Fet" } function Start-Isard { param( [Parameter(Position = 0, Mandatory = $true, HelpMessage = "Nom de la màquina virtual")] [string] $Name, [switch] $Wait ) #https://gitlab.com/isard/isardvdi/-/blob/main/api/src/api/views/DesktopsPersistentView.py $vm = Get-Isard -Name $Name -Raw if ($Null -eq $vm) { Write-IsardLog $Name Write-Host -ForegroundColor Red "No existeix cap màquina amb aquest nom" return } if ($vm.state -eq "Started") { Write-IsardLog $Name Write-Host -ForegroundColor Yellow "La màquina ja està engegada" return } if ($vm.state -eq "Shutting-down") { Stop-Isard $Name -Wait } if ($vm.state -eq "WaitingIP") { Write-IsardLog $Name Write-Host -ForegroundColor Yellow "La màquina està esperant la IP" -NoNewLine Write-Host " ..." -NoNewLine } else { $endpoint = "/api/v3/desktop/start/$($vm.id)" Write-IsardLog $Name Write-Host "Engegant la màquina ..." -NoNewline $data = Invoke-IsardRequest -Endpoint $endpoint # TODO check ok {"id": "ba4d3752-7dd5-49e2-8fd9-b237eaeea4f5"} } if ($Wait) { $state = "" while ($state -ne "Started") { Start-Sleep -Seconds 1 Write-Host "." -NoNewline $vm = Get-Isard -Name $Name -Raw $state = $vm.state } } Write-Host " " -NoNewline Write-Host -ForegroundColor Green "Fet" } function Stop-Isard { param( [Parameter(Position = 0, Mandatory = $true, HelpMessage = "Nom de la màquina virtual")] [string] $Name, [switch] $Wait ) #https://gitlab.com/isard/isardvdi/-/blob/main/api/src/api/views/DesktopsPersistentView.py $vm = Get-Isard -Name $Name -Raw if ($Null -eq $vm) { Write-IsardLog $Name Write-Host -ForegroundColor Red "No existeix cap màquina amb aquest nom" return } if ($vm.state -eq "Stopped") { Write-IsardLog $Name Write-Host -ForegroundColor Yellow "La màquina ja està aturada" return } if ($vm.state -eq "Shutting-down") { Write-IsardLog $Name Write-Host -ForegroundColor Yellow "La màquina s'està aturant ..." -NoNewline } else { $endpoint = "/api/v3/desktop/stop/$($vm.id)" Write-IsardLog $Name Write-Host "Aturant la màquina ..." -NoNewline $data = Invoke-IsardRequest -Endpoint $endpoint # TODO check ok {"id": "ba4d3752-7dd5-49e2-8fd9-b237eaeea4f5"} } if ($Wait) { $state = "" while ($state -ne "Stopped") { Start-Sleep -Seconds 1 Write-Host "." -NoNewline $vm = Get-Isard -Name $Name -Raw $state = $vm.state } } Write-Host " " -NoNewline Write-Host -ForegroundColor Green "Fet" } ##### Private function Get-IsardPath { param( [string] $Name ) $path = Get-BoxPath -Path "isard" if ($Name) { $path = Join-Path $path $Name } return $path } # https://gitlab.com/isard/isardvdi/-/blob/main/api/src/api/views/AuthenticationView.py function Get-IsardToken { param ( [switch] $Update ) $tokenFile = Get-IsardPath -Name token if ($Update) { Remove-Item -Path $tokenFile } if (Test-Path $tokenFile) { return (Get-Content $tokenFile) } $login = @{ "category" = @{"name" = "Provençana"; "id" = "db79b78a-5408-4ff9-9853-a1172b7eadb2" }; "username" = $Null } $loginPath = Get-IsardPath "login.json" if (Test-Path $loginPath -PathType Leaf) { $login = (Get-Content $loginPath) | ConvertFrom-Json } Write-Host -ForegroundColor Green "Inciar Sessió" if (!($categoryId = Read-Host "Institut [$($login.category.name)]")) { $categoryId = $login.category.id } if (!($username = Read-Host "Nom d'usuari [$($login.username)]")) { $username = $login.username } $login.username = $username $password = Read-Host "Contrasenya" -AsSecureString $password = (New-Object PSCredential 0, $password).GetNetworkCredential().Password $endpoint = "/authentication/login" $response = Invoke-IsardRequest2 -Endpoint $endpoint -Form $True -Data @{ provider = "p:form" category_id = "p:$categoryId" username = $username password = $password } $token = $response.Content $token | Out-File $tokenFile $login | ConvertTo-Json | Out-File $loginPath return $token } function Invoke-IsardRequest { param( [string] $Endpoint, [hashtable] $Data, [bool] $Form = $False ) try { $token = Get-IsardToken try { $response = Invoke-IsardRequest2 -Endpoint $Endpoint -Data $Data -Form $Form -Token $token return $response.Content } catch { $status = [int]$_.Exception.Response.StatusCode if ($status -ne 401) { throw $_.Exception } $token = Get-IsardToken -Update $response = Invoke-IsardRequest2 -Endpoint $Endpoint -Data $Data -Form $Form -Token $token return $response } } catch { $response = $_.Exception.Response #StatusDescription Write-IsardLog "HTTP" Write-Host -ForegroundColor Yellow "($([int]$response.StatusCode) $($response.StatusCode))" -NoNewline Write-Host ": " -NoNewline Write-Host $_.ErrorDetails.Message throw $_.Exception } } function Invoke-IsardRequest2 { param( [string] $Endpoint, [hashtable] $Data, [bool] $Form, [string] $Token ) $uri = "https://pilotfp.gencat.isardvdi.com${Endpoint}" $headers = @() $method = "Get" $contentType = $Null $body = $Null if ($Null -ne $Token) { $headers = @{Authorization = "Bearer $token" } } if ($Null -ne $Data) { $method = "Post" if (-Not($Form)) { $contentType = "application/json" $body = $Data | ConvertTo-Json -Depth 10 } else { $boundary = [System.Guid]::NewGuid().ToString(); $contentType = "multipart/form-data; boundary=`"$boundary`"" $LF = "`r`n" $query = $Null $body = @() foreach ($item in $Data.GetEnumerator()) { $body += "--$boundary" $body += "Content-Disposition: form-data; name=`"$($item.Name)`"$LF" $value = $item.Value if (-Not($value.StartsWith("p:"))) { $body += $value } else { $value = $value.Substring(2) $body += $value if ($Null -eq $query) { $query += "?" } else { $query += "&" } $query += "$($item.Name)=$value" } } $body += "--$boundary--$LF" $body = $body -join $LF if ($Null -ne $query) { $uri += $query } } } $ProgressPreference = "SilentlyContinue" $response = Invoke-WebRequest -UseBasicParsing -Method $method -Uri $uri -Header $headers -ContentType $contentType -Body $body $ProgressPreference = "Continue" # session https://superuser.com/questions/1275923/using-invoke-webrequest-in-powershell-with-cookies $setCookie = $response.Headers['Set-Cookie'] return $response } function Write-IsardLog { param( [string] $Name ) Write-Host -ForegroundColor Blue -NoNewline $Name Write-Host ": " -NoNewline } $isard_templates = @{ ubuntu = @{ "template_id" = "23f44236-d6df-43eb-9f00-e113d1e23997" # Ubuntu Mate Desktop 24.04 LTS v1.1 "name" = $Null "description" = "" "guest_properties" = @{ "credentials" = @{ "username" = "box" "password" = "password" } "fullscreen" = $False "viewers" = @{ "browser_rdp" = @{ "options" = "null" } "browser_vnc" = @{ "options" = "null" } "file_rdpgw" = @{ "options" = "null" } "file_spice" = @{ "options" = "null" } } } "hardware" = @{ "boot_order" = @("disk") "disk_bus" = "default" "disks" = @( @{ "bus" = "virtio" "storage_id" = "62d93be1-cfb1-4397-b6eb-bf42f003d0ae" } ) "floppies" = @() "interfaces" = @("default", "wireguard") "isos" = @() "memory" = 6 "vcpus" = 4 "videos" = @("default") "reservables" = @{ "vgpus" = @("None") } } "image" = @{ "id" = "os_ubuntu.png" "type" = "stock" } } windows = @{ "template_id" = "fd44d7c5-0a05-4a6f-a7df-a1a87a85da90" # Windows 11 T3_Isardvdi_v2.0 "name" = $Null "description" = "" "guest_properties" = @{ "credentials" = @{ "username" = "box" "password" = "password" } "fullscreen" = $False "viewers" = @{ "browser_rdp" = @{ "options" = "null" } "browser_vnc" = @{ "options" = "null" } "file_rdpgw" = @{ "options" = "null" } "file_spice" = @{ "options" = "null" } } } "hardware" = @{ "boot_order" = @("disk") "disk_bus" = "sata" "disks" = @( @{ "bus" = "sata" "storage_id" = "d2d17c23-eec8-40c5-8c88-51719f792834" } ) "floppies" = @() "interfaces" = @("default", "wireguard") "isos" = @() "memory" = 8 "vcpus" = 4 "videos" = @("default") "reservables" = @{ "vgpus" = @("None") } } "image" = @{ "id" = "os_windows.png" "type" = "stock" } } } |