added install-dattormm and folded multiple function into it

This commit is contained in:
2025-07-02 21:25:19 -04:00
parent 20d398c57c
commit 50fee51725

View File

@@ -97,19 +97,23 @@
# ───────────────────────────────────────────────────────── # ─────────────────────────────────────────────────────────
# Datto headless mode # Datto headless mode
# Both Datto sets share the webhook password # ─── DattoFetch & DattoInstall share the webhook creds ─────────────
# Shared webhook password for both Datto modes
[Parameter(Mandatory,ParameterSetName='DattoFetch')] [Parameter(Mandatory,ParameterSetName='DattoFetch')]
[Parameter(Mandatory,ParameterSetName='DattoInstall')] [Parameter(Mandatory,ParameterSetName='DattoInstall')]
[string]$N8nPassword, [switch]$UseWebhook,
# ───────────────────────────────────────────────────────── [Parameter(Mandatory,ParameterSetName='DattoFetch')]
# Fetch only set write sites and exit [Parameter(Mandatory,ParameterSetName='DattoInstall')]
[Parameter(ParameterSetName='DattoFetch')][switch] $SaveSitesOnly, [string]$WebhookPassword,
[Parameter(ParameterSetName='DattoFetch')][string] $OutputFile = 'datto_sites.csv',
# ───────────────────────────────────────────────────────── [string]$WebhookUrl = $Global:DattoWebhookUrl,
# Install set: target site must be provided
# ─── only DattoFetch uses these ────────────────────────────────────
[Parameter(ParameterSetName='DattoFetch')][switch]$FetchSites,
[Parameter(ParameterSetName='DattoFetch')][switch] $SaveSitesList,
[Parameter(ParameterSetName='DattoFetch')][ValidatePattern('\.csv$|\.json$','i')][string] $OutputFile = 'datto_sites.csv',
# ─── only DattoInstall uses these ─────────────────────────────────
[Parameter(Mandatory,ParameterSetName='DattoInstall')][string] $SiteUID, [Parameter(Mandatory,ParameterSetName='DattoInstall')][string] $SiteUID,
[Parameter(Mandatory,ParameterSetName='DattoInstall')][string] $SiteName, [Parameter(Mandatory,ParameterSetName='DattoInstall')][string] $SiteName,
[Parameter(ParameterSetName='DattoInstall')][switch] $PushSiteVars, [Parameter(ParameterSetName='DattoInstall')][switch] $PushSiteVars,
@@ -175,101 +179,7 @@
#endregion SVS Module #endregion SVS Module
#region Get-DattoApiCredentials
function Get-DattoApiCredentials {
[CmdletBinding()]
param (
[Parameter(Mandatory)][string]$Password
)
$headers = @{ "SVSMSPKit" = $Password }
try {
$resp = Invoke-RestMethod -Uri $Global:DattoWebhookUrl `
-Headers $headers `
-Method GET
return @{
ApiUrl = $resp.ApiUrl
ApiKey = $resp.ApiKey
ApiSecretKey = $resp.ApiSecretKey
}
}
catch {
Write-LogHybrid "Failed to fetch API credentials: $($_.Exception.Message)" Error DattoAuth
return $null
}
}
#endregion Get-DattoApiCredentials
#region Get-DattoRMMSites
function Get-DattoRmmSites {
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[string] $Password,
[Parameter()]
[string] $WebhookUrl = $Global:DattoWebhookUrl
)
# 1) Fetch Datto API credentials from your webhook
Write-Verbose "Fetching Datto API credentials from $WebhookUrl"
try {
$headers = @{ 'SVSMSPKit' = $Password }
$creds = Invoke-RestMethod -Uri $WebhookUrl -Headers $headers -Method GET
}
catch {
Throw "Failed to fetch credentials from webhook: $_"
}
$apiUrl = $creds.ApiUrl
$apiKey = $creds.ApiKey
$apiSecretKey = $creds.ApiSecretKey
# 2) Request an OAuth token
Write-Verbose "Requesting OAuth token from $apiUrl/auth/oauth/token"
try {
$securePwd = ConvertTo-SecureString -String 'public' -AsPlainText -Force
$credObj = New-Object System.Management.Automation.PSCredential('public-client', $securePwd)
$tokenResp = Invoke-RestMethod `
-Uri "$apiUrl/auth/oauth/token" `
-Credential $credObj `
-Method 'POST' `
-ContentType 'application/x-www-form-urlencoded' `
-Body "grant_type=password&username=$apiKey&password=$apiSecretKey"
$token = $tokenResp.access_token
}
catch {
Throw "Failed to obtain OAuth token: $_"
}
# 3) Fetch the list of RMM sites
Write-Verbose "Fetching RMM sites from $apiUrl/api/v2/account/sites"
try {
$authHeader = @{ Authorization = "Bearer $token" }
$sitesResp = Invoke-RestMethod `
-Uri "$apiUrl/api/v2/account/sites" `
-Method 'GET' `
-Headers $authHeader `
-ContentType 'application/json'
$siteList = $sitesResp.sites | Select-Object `
@{ Name = 'Name'; Expression = { $_.name } }, `
@{ Name = 'UID'; Expression = { $_.uid } }
if (-not $siteList) {
Write-Warning "No sites were returned by the API."
return @()
}
return $siteList
}
catch {
Throw "Failed to fetch sites from API: $_"
}
}
#endregion Get-DattoRMMSites
#region Write-Log #region Write-Log
@@ -1083,7 +993,6 @@ $script
$Context.Response.OutputStream.Close() $Context.Response.OutputStream.Close()
} }
# new helper to return JSON
function Respond-JSON { function Respond-JSON {
param($Context, $Object) param($Context, $Object)
$json = $Object | ConvertTo-Json -Depth 5 $json = $Object | ConvertTo-Json -Depth 5
@@ -1095,266 +1004,289 @@ $script
} }
function Handle-FetchSites { function Handle-FetchSites {
param($Context)
# 1) Read incoming JSON (using block auto-disposes the reader)
$reader = [IO.StreamReader]::new($Context.Request.InputStream)
try {
$raw = $reader.ReadToEnd()
} finally {
$reader.Close()
}
try {
$pw = (ConvertFrom-Json $raw).password
} catch {
Write-LogHybrid "Invalid JSON in /getpw payload: $($_.Exception.Message)" "Error" "FetchSites"
returnRespondEmpty $Context
return
}
# 2) Fetch your Datto API creds from the webhook
Write-LogHybrid "Calling webhook for Datto credentials…" "Info" "FetchSites"
try {
$creds = Get-DattoApiCredentials -Password $pw
if (-not $creds) {
Write-LogHybrid "Webhook returned no credentials" Error FetchSites
returnRespondEmpty $Context 403
return
}
# reuse the same globals from the entrypoint
$Global:ApiUrl = $creds.ApiUrl
$Global:ApiKey = $creds.ApiKey
$Global:ApiSecretKey = $creds.ApiSecretKey
Write-LogHybrid "Fetched and stored API credentials." Success FetchSites
} catch {
Write-LogHybrid "Credential-fetch error: $($_.Exception.Message)" Error FetchSites -LogToEvent
returnRespondEmpty $Context 500
return
}
# 3) Exchange for a bearer token
Write-LogHybrid "Requesting OAuth token" "Info" "FetchSites"
try {
$securePublic = ConvertTo-SecureString 'public' -AsPlainText -Force
$creds = New-Object System.Management.Automation.PSCredential('public-client',$securePublic)
$tokenResp = Invoke-RestMethod `
-Uri "$Global:ApiUrl/auth/oauth/token" `
-Credential $creds `
-Method Post `
-ContentType 'application/x-www-form-urlencoded' `
-Body "grant_type=password&username=$Global:ApiKey&password=$Global:ApiSecretKey"
$token = $tokenResp.access_token
Write-LogHybrid "OAuth token acquired." "Success" "FetchSites"
} catch {
Write-LogHybrid "OAuth request failed: $($_.Exception.Message)" "Error" "FetchSites"
returnRespondEmpty $Context 500
return
}
# 4) Pull the site list
Write-LogHybrid "Fetching Datto RMM site list" "Info" "FetchSites"
try {
$hdr = @{ Authorization = "Bearer $token" }
$sitesResp = Invoke-RestMethod -Uri "$Global:ApiUrl/api/v2/account/sites" `
-Method Get `
-Headers $hdr `
-ContentType 'application/json'
$siteList = $sitesResp.sites | ForEach-Object {
[PSCustomObject]@{ Name = $_.name; UID = $_.uid }
}
Write-LogHybrid "Site list retrieved ($($siteList.Count) sites)." "Success" "FetchSites"
} catch {
Write-LogHybrid "Failed to fetch site list: $($_.Exception.Message)" "Error" "FetchSites"
returnRespondEmpty $Context 500
return
}
# 5) Return JSON array
$json = $siteList | ConvertTo-Json -Depth 2
$bytes = [Text.Encoding]::UTF8.GetBytes($json)
$Context.Response.ContentType = 'application/json'
$Context.Response.ContentLength64 = $bytes.Length
$Context.Response.OutputStream.Write($bytes, 0, $bytes.Length)
$Context.Response.OutputStream.Close()
}
# Helper function to consistently return an empty JSON array
function returnRespondEmpty {
param(
[Parameter(Mandatory)][object]$Context,
[Parameter(Mandatory)][ValidateRange(100,599)][int]$StatusCode = 500
)
# Always return an empty JSON array body
$empty = [Text.Encoding]::UTF8.GetBytes("[]")
# Set the desired status code and headers
$Context.Response.StatusCode = $StatusCode
$Context.Response.ContentType = 'application/json'
$Context.Response.ContentLength64 = $empty.Length
# Write and close
$Context.Response.OutputStream.Write($empty, 0, $empty.Length)
$Context.Response.OutputStream.Close()
}
# On-boarding handlers
function Handle-SetSVSPowerPlan {
param($Context)
# 1) call into your module
Set-SVSPowerPlan
# 2) log & write back a simple text response
Write-LogHybrid "PowerPlan set" "Success" "OnBoard"
Respond-Text $Context "PowerPlan applied"
}
function Handle-InstallSVSMSP {
param($Context)
Write-LogHybrid "HTTP trigger: Handle-InstallSVSMSP" "Info" "OnBoard"
try {
Install-SVSMSP -InstallToolkit
Respond-Text $Context "SVSMSP Module installed/updated."
} catch {
Write-LogHybrid "Error in Install-SVSMSP: $_" "Error" "OnBoard"
Respond-Text $Context "ERROR: $_"
}
}
function Handle-InstallCyberQP {
param($Context)
# 1) call into your module
Install-CyberQP
# 2) log & write back a simple text response
Write-LogHybrid "CyberQP installed" "Success" "OnBoard"
Respond-Text $Context "CyberQP installed"
}
function Handle-InstallThreatLocker {
param($Context)
# 1) call into your module
Install-ThreatLocker
# 2) log & write back a simple text response
Write-LogHybrid "ThreatLocker installed" "Success" "OnBoard"
Respond-Text $Context "ThreatLocker installed"
}
function Handle-InstallRocketCyber {
param($Context)
# 1) call into your module
Install-RocketCyber
# 2) log & write back a simple text response
Write-LogHybrid "RocketCyber installed" "Success" "OnBoard"
Respond-Text $Context "RocketCyber installed"
}
function Handle-InstallSVSHelpDesk {
param($Context)
# 1) call into your module
Install-SVSHelpDesk
# 2) log & write back a simple text response
Write-LogHybrid "SVS HelpDesk installed" "Success" "OnBoard"
Respond-Text $Context "SVS HelpDesk installed"
}
function Handle-InstallDattoRMM {
param($Context) param($Context)
$req = $Context.Request
$resp = $Context.Response
if ($req.HttpMethod -ne 'POST') {
$resp.StatusCode = 405; $resp.ContentType = 'text/plain'
$resp.OutputStream.Write([Text.Encoding]::UTF8.GetBytes('Use POST'),0,7)
$resp.OutputStream.Close(); return
}
# parse JSON body
$body = (New-Object IO.StreamReader $req.InputStream).ReadToEnd()
$data = $body | ConvertFrom-Json
$checked = $data.checkedValues
$uid = $data.UID
$name = $data.Name
try { try {
Install-DattoRMM ` # 1) Read the incoming JSON payload (contains only the webhook password)
-ApiUrl $Global:ApiUrl ` $raw = (New-Object IO.StreamReader $Context.Request.InputStream).ReadToEnd()
-ApiKey $Global:ApiKey ` $pw = (ConvertFrom-Json $raw).password
-ApiSecretKey $Global:ApiSecretKey `
-SiteUID $uid `
-SiteName $name `
-PushSiteVars:($checked -contains 'inputVar') `
-InstallRMM: ($checked -contains 'rmm') `
-SaveCopy: ($checked -contains 'exe')
Write-LogHybrid "RMM install triggered for $name" "Success" "DattoRMM" # 2) Delegate to your unified function
$resp.StatusCode = 200 $sites = Install-DattoRMM `
$responseString = "Triggered DattoRMM for $name" -UseWebhook `
-WebhookPassword $pw `
-FetchSites `
-SaveSitesList:$SaveSitesList `
-OutputFile $OutputFile
# 3) Return JSON array of sites
Respond-JSON $Context $sites
} }
catch { catch {
Write-LogHybrid "Error in Install-DattoRMM: $_" "Error" "DattoRMM" # Log the exception and return HTTP 500
$resp.StatusCode = 500 Write-LogHybrid "Handle-FetchSites error: $($_.Exception.Message)" Error DattoRMM
$responseString = "ERROR: $($_.Exception.Message)" $Context.Response.StatusCode = 500
Respond-Text $Context "Internal server error fetching sites."
}
}
function Handle-InstallDattoRMM {
param($Context)
try {
if ($Context.Request.HttpMethod -ne 'POST') {
$Context.Response.StatusCode = 405
Respond-Text $Context 'Use POST'
return
}
# 1) Read and parse the JSON body
$body = (New-Object IO.StreamReader $Context.Request.InputStream).ReadToEnd()
$data = ConvertFrom-Json $body
# 2) Delegate to your unified function for the install
Install-DattoRMM `
-UseWebhook `
-WebhookPassword $Global:WebhookPassword `
-SiteUID $data.UID `
-SiteName $data.Name `
-PushSiteVars:($data.checkedValues -contains 'inputVar') `
-InstallRMM: ($data.checkedValues -contains 'rmm') `
-SaveCopy: ($data.checkedValues -contains 'exe')
# 3) Acknowledge to the client
Respond-Text $Context "Triggered DattoRMM for $($data.Name)"
}
catch {
# Log the exception and return HTTP 500
Write-LogHybrid "Handle-InstallDattoRMM error: $($_.Exception.Message)" Error DattoRMM
$Context.Response.StatusCode = 500
Respond-Text $Context "Internal server error during DattoRMM install."
}
}
#endregion Handler Stubs
#region Install-DattoRMM
<#
.SYNOPSIS
Installs/configures the Datto RMM agent, fetches site lists, and optionally saves the site list to disk.
.DESCRIPTION
Centralizes Datto RMM operations in one function:
- Fetch API credentials from a webhook (-UseWebhook)
- Acquire OAuth token
- Fetch site list (-FetchSites)
- Save site list to Desktop as JSON or CSV (-FetchSites + -SaveSitesList)
- Write site variables to registry (-PushSiteVars)
- Download & launch the RMM agent installer (-InstallRMM)
- Save a copy of the installer (-SaveCopy)
.PARAMETER UseWebhook
Fetches ApiUrl, ApiKey, and ApiSecretKey from the webhook when used with WebhookPassword.
.PARAMETER WebhookPassword
Password for authenticating to the credentials webhook.
.PARAMETER WebhookUrl
URL of the credentials webhook. Defaults to $Global:DattoWebhookUrl.
.PARAMETER ApiUrl
Direct Datto API endpoint URL (if not using webhook).
.PARAMETER ApiKey
Direct Datto API key (if not using webhook).
.PARAMETER ApiSecretKey
Direct Datto API secret (if not using webhook).
.PARAMETER FetchSites
Fetches the list of sites and skips all install steps.
.PARAMETER SaveSitesList
Saves the fetched site list to Desktop using OutputFile. Must be used with -FetchSites.
.PARAMETER OutputFile
Filename for saving the site list (.json or .csv). Defaults to 'datto_sites.csv'.
.PARAMETER PushSiteVars
Writes fetched site variables into HKLM:\Software\SVS\Deployment.
.PARAMETER InstallRMM
Downloads and runs the Datto RMM agent installer.
.PARAMETER SaveCopy
Saves a copy of the downloaded agent installer to C:\Temp.
.PARAMETER SiteUID
Unique identifier of the Datto site (required for install and registry push).
.PARAMETER SiteName
Friendly name of the Datto site (used for logging).
.EXAMPLE
# Fetch and save site list via webhook
Install-DattoRMM -UseWebhook -WebhookPassword 'Tndmeeisdwge!' -FetchSites -SaveSitesList -OutputFile 'sites.csv'
.EXAMPLE
# Headless install with site variables
Install-DattoRMM -ApiUrl 'https://api.example.com' -ApiKey 'KeyHere' -ApiSecretKey 'SecretHere' \
-SiteUID 'site-123' -SiteName 'Acme Corp' -PushSiteVars -InstallRMM
.EXAMPLE
# Download and save installer to C:\Temp without installing
Install-DattoRMM -ApiUrl 'https://api.example.com' -ApiKey 'KeyHere' -ApiSecretKey 'SecretHere' \
-SiteUID 'site-123' -SiteName 'Acme Corp' -SaveCopy
#>
function Install-DattoRMM {
[CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact='Medium')]
param (
[switch]$UseWebhook,
[string]$WebhookPassword,
[string]$WebhookUrl = $Global:DattoWebhookUrl,
[string]$ApiUrl,
[string]$ApiKey,
[string]$ApiSecretKey,
[switch]$FetchSites,
[switch]$SaveSitesList,
[string]$OutputFile = 'datto_sites.csv',
[switch]$PushSiteVars,
[switch]$InstallRMM,
[switch]$SaveCopy,
[string]$SiteUID,
[string]$SiteName
)
# Validate mutually-dependent switches
if ($SaveSitesList -and -not $FetchSites) {
Write-LogHybrid "-SaveSitesList requires -FetchSites." Error DattoRMM; return
} }
$b = [Text.Encoding]::UTF8.GetBytes($responseString) # 1) Optionally fetch credentials from webhook
$resp.ContentType = 'text/plain' if ($UseWebhook) {
$resp.ContentLength64 = $b.Length if (-not $WebhookPassword) {
$resp.OutputStream.Write($b,0,$b.Length) Write-LogHybrid "Webhook password missing." Error DattoRMM; return
$resp.OutputStream.Close() }
} try {
$resp = Invoke-RestMethod -Uri $WebhookUrl `
-Headers @{ SVSMSPKit = $WebhookPassword } `
-Method GET
$ApiUrl = $resp.ApiUrl
$ApiKey = $resp.ApiKey
$ApiSecretKey = $resp.ApiSecretKey
Write-LogHybrid "Webhook credentials fetched." Success DattoRMM
} catch {
Write-LogHybrid "Failed to fetch webhook credentials: $($_.Exception.Message)" Error DattoRMM; return
}
}
# 2) Validate API parameters
if (-not $ApiUrl -or -not $ApiKey -or -not $ApiSecretKey) {
Write-LogHybrid "Missing required API parameters." Error DattoRMM; return
}
# 3) Acquire OAuth token
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
try {
$publicCred = New-Object System.Management.Automation.PSCredential(
'public-client', (ConvertTo-SecureString 'public' -AsPlainText -Force)
)
$tokenResp = Invoke-RestMethod -Uri "$ApiUrl/auth/oauth/token" `
-Credential $publicCred `
-Method Post `
-ContentType 'application/x-www-form-urlencoded' `
-Body "grant_type=password&username=$ApiKey&password=$ApiSecretKey"
$token = $tokenResp.access_token
Write-LogHybrid "OAuth token acquired." Success DattoRMM
} catch {
Write-LogHybrid "OAuth token fetch failed: $($_.Exception.Message)" Error DattoRMM; return
}
$headers = @{ Authorization = "Bearer $token" }
# 4) Fetch site list only
if ($FetchSites) {
try {
$sitesResp = Invoke-RestMethod -Uri "$ApiUrl/api/v2/account/sites" -Method Get -Headers $headers
$siteList = $sitesResp.sites | ForEach-Object {
[PSCustomObject]@{ Name = $_.name; UID = $_.uid }
}
Write-LogHybrid "Fetched $($siteList.Count) sites." Success DattoRMM
if ($SaveSitesList) {
$desktop = [Environment]::GetFolderPath('Desktop')
$path = Join-Path $desktop $OutputFile
$ext = [IO.Path]::GetExtension($OutputFile).ToLower()
if ($ext -eq '.json') {
$siteList | ConvertTo-Json -Depth 3 | Out-File -FilePath $path -Encoding UTF8
} else {
$siteList | Export-Csv -Path $path -NoTypeInformation -Encoding UTF8
}
Write-LogHybrid "Wrote $($siteList.Count) sites to $path" Success DattoRMM
}
return $siteList
} catch {
Write-LogHybrid "Failed to fetch sites: $($_.Exception.Message)" Error DattoRMM; return @()
}
}
# 5) Push site variables to registry
if ($PushSiteVars) {
try {
$varsResp = Invoke-RestMethod -Uri "$ApiUrl/api/v2/site/$SiteUID/variables" -Method Get -Headers $headers
Write-LogHybrid "Fetched variables for '$SiteName'." Success DattoRMM
} catch {
Write-LogHybrid "Variable fetch failed: $($_.Exception.Message)" Error DattoRMM
}
$regPath = "HKLM:\Software\SVS\Deployment"
foreach ($v in $varsResp.variables) {
try {
if (-not (Test-Path $regPath)) { New-Item -Path $regPath -Force | Out-Null }
New-ItemProperty -Path $regPath -Name $v.name -Value $v.value -PropertyType String -Force | Out-Null
Write-LogHybrid "Wrote '$($v.name)' to registry." Success DattoRMM
} catch {
Write-LogHybrid "Failed to write '$($v.name)': $($_.Exception.Message)" Error DattoRMM
}
}
}
# 6) Download & install RMM agent
if ($InstallRMM) {
if ($PSCmdlet.ShouldProcess("Site '$SiteName'", "Install RMM agent")) {
try {
$dlUrl = "https://zinfandel.centrastage.net/csm/profile/downloadAgent/$SiteUID"
$tmp = "$env:TEMP\AgentInstall.exe"
Invoke-WebRequest -Uri $dlUrl -OutFile $tmp -UseBasicParsing
Write-LogHybrid "Downloaded agent to $tmp." Info DattoRMM
Start-Process -FilePath $tmp -NoNewWindow
Write-LogHybrid "RMM agent installer launched." Success DattoRMM
} catch {
Write-LogHybrid "Agent install failed: $($_.Exception.Message)" Error DattoRMM
}
}
}
# 7) Save a copy of installer to C:\Temp
if ($SaveCopy) {
try {
$dlUrl = "https://zinfandel.centrastage.net/csm/profile/downloadAgent/$SiteUID"
$path = "C:\Temp\AgentInstall.exe"
if (-not (Test-Path 'C:\Temp')) { New-Item -Path 'C:\Temp' -ItemType Directory | Out-Null }
Invoke-WebRequest -Uri $dlUrl -OutFile $path -UseBasicParsing
Write-LogHybrid "Saved installer copy to $path." Info DattoRMM
} catch {
Write-LogHybrid "Save-copy failed: $($_.Exception.Message)" Error DattoRMM
}
}
# 8) Warn if no action was taken
if (-not ($PushSiteVars -or $InstallRMM -or $SaveCopy)) {
Write-LogHybrid "No action specified. Use -FetchSites, -SaveSitesList, -PushSiteVars, -InstallRMM, or -SaveCopy." Warning DattoRMM
}
}
# Off-boarding handlers #endregion Install-DattoRMM
function Handle-UninstallCyberQP {
param($Context)
# 1) call into your module
Uninstall-CyberQP
Write-LogHybrid "CyberQP uninstalled" "Success" "OffBoard"
Respond-Text $Context "CyberQP uninstalled"
}
function Cleanup-SVSMSP {
param($Context)
Write-LogHybrid "SVSMSP cleaned up" "Success" "OffBoard"
Respond-Text $Context "SVSMSP cleaned up"
}
# Tweaks handler
function Disable-Animations {
param($Context)
Write-LogHybrid "Animations disabled" "Success" "Tweaks"
Respond-Text $Context "Animations disabled"
}
# SVSApps handler
function Install-WingetLastPass {
param($Context)
Write-LogHybrid "Winget LastPass installed" "Success" "SVSApps"
Respond-Text $Context "Winget LastPass installed"
}
#endregion Handler Stubs
#region Dispatch-Request #region Dispatch-Request
@@ -1426,30 +1358,16 @@ $script
'DattoFetch' { 'DattoFetch' {
Write-LogHybrid "Fetching site list only…" Info DattoAuth Write-LogHybrid "Fetching site list only…" Info DattoAuth
$sites = Get-DattoRmmSites -Password $N8nPassword $sites = Install-DattoRMM `
-UseWebhook `
-WebhookPassword $WebhookPassword `
-FetchSites `
-SaveSitesList:$SaveSitesList `
-OutputFile $OutputFile
if ($SaveSitesOnly) { Write-LogHybrid "Done." Success DattoAuth
# If SaveSitesOnly is true, save the output to a file on desktop return
$desktopPath = [System.Environment]::GetFolderPath('Desktop') }
$filePath = Join-Path -Path $desktopPath -ChildPath $OutputFile
$ext = [IO.Path]::GetExtension($OutputFile).ToLower()
if ($ext -eq '.json') {
# Save the file to the desktop using the full path
$sites | ConvertTo-Json -Depth 3 | Out-File -FilePath $filePath -Encoding UTF8
} else {
# Save the file to the desktop using the full path
$sites | Export-Csv -Path $filePath -NoTypeInformation -Encoding UTF8
}
Write-LogHybrid "Wrote $($sites.Count) sites to $filePath" Success DattoAuth
} else {
# If SaveSitesOnly is not true, just fetch sites (for UI purposes or silent mode without saving)
Write-LogHybrid "Sites fetched successfully, but not saved." Success DattoAuth
}
return
}
# ──────────────────────────────────────────── # ────────────────────────────────────────────
@@ -1458,16 +1376,16 @@ $script
'DattoInstall' { 'DattoInstall' {
Write-LogHybrid "Headless DattoRMM deploy" Info DattoAuth Write-LogHybrid "Headless DattoRMM deploy" Info DattoAuth
if ($PSCmdlet.ShouldProcess("Datto site '$SiteName'", "Headless install")) { if ($PSCmdlet.ShouldProcess("Datto site '$SiteName'", "Headless install")) {
Install-DattoRMM ` Install-DattoRMM `
-ApiUrl $Global:ApiUrl ` -UseWebhook `
-ApiKey $Global:ApiKey ` -WebhookPassword $WebhookPassword `
-ApiSecretKey $Global:ApiSecretKey ` -SiteUID $SiteUID `
-SiteUID $SiteUID ` -SiteName $SiteName `
-SiteName $SiteName ` -PushSiteVars:$PushSiteVars `
-PushSiteVars:$PushSiteVars ` -InstallRMM:$InstallRMM `
-InstallRMM:$InstallRMM ` -SaveCopy:$SaveCopy
-SaveCopy:$SaveCopy
} }
return return
@@ -1532,59 +1450,7 @@ $script
#endregion #endregion
#region Install-DattoRMM-Helper
function Install-DattoRMM-Helper {
param (
[string]$ApiUrl,
[string]$ApiKey,
[string]$ApiSecretKey,
[switch]$FetchSitesOnly,
[string]$SiteName,
[string]$SiteUID
)
if (-not $ApiUrl -or -not $ApiKey -or -not $ApiSecretKey) {
Write-LogHybrid -Message "Missing required parameters. Please provide ApiUrl, ApiKey, and ApiSecretKey." -Level "Error" -LogToEvent
return
}
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Write-LogHybrid -Message "Fetching OAuth token..." -Level "Info"
try {
$securePassword = ConvertTo-SecureString -String 'public' -AsPlainText -Force
$apiGenToken = Invoke-WebRequest -Credential (New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList ('public-client', $securePassword)) `
-Uri ('{0}/auth/oauth/token' -f $ApiUrl) `
-Method 'POST' `
-ContentType 'application/x-www-form-urlencoded' `
-Body ('grant_type=password&username={0}&password={1}' -f $ApiKey, $ApiSecretKey) `
| ConvertFrom-Json
$requestToken = $apiGenToken.access_token
Write-LogHybrid -Message "OAuth token fetched successfully." -Level "Success" -LogToEvent
} catch {
Write-LogHybrid -Message "Failed to fetch OAuth token. Details: $($_.Exception.Message)" -Level "Error" -LogToEvent
return
}
$getHeaders = @{"Authorization" = "Bearer $requestToken"}
if ($FetchSitesOnly) {
Write-Host "Fetching list of sites from the Datto RMM API..." -ForegroundColor Cyan
try {
$getHeaders = @{"Authorization" = "Bearer $requestToken" }
$getSites = Invoke-WebRequest -Uri "$ApiUrl/api/v2/account/sites" -Method Get -Headers $getHeaders -ContentType "application/json"
$sitesJson = $getSites.Content | ConvertFrom-Json
$siteList = $sitesJson.sites | ForEach-Object {
[PSCustomObject]@{
Name = $_.name
UID = $_.uid
}
}
Write-Host "Successfully fetched list of sites." -ForegroundColor Green
return $siteList
}
catch {
Write-Host "Failed to fetch sites from the API. Details: $($_.Exception.Message)" -ForegroundColor Red
return
}
}
}
#endregion
#region HTTP Listener & Routing #region HTTP Listener & Routing