From c3e3e38f2102bed083a090ff5d49f336e09bcc4c Mon Sep 17 00:00:00 2001 From: soybigmac Date: Mon, 31 Aug 2026 00:02:32 -0400 Subject: [PATCH 01/10] feat: add Device Notes support (6 endpoints) - Get-NCDeviceNotes: list notes with pagination - New-NCDeviceNote: add note to single device or bulk (POST /devices/notes) - Set-NCDeviceNote: modify a note (PUT) - Remove-NCDeviceNote: delete single or batch notes --- Public/Get-NCDeviceNotes.ps1 | 49 ++++++++++++++++++++++ Public/New-NCDeviceNote.ps1 | 74 ++++++++++++++++++++++++++++++++++ Public/Remove-NCDeviceNote.ps1 | 61 ++++++++++++++++++++++++++++ Public/Set-NCDeviceNote.ps1 | 43 ++++++++++++++++++++ 4 files changed, 227 insertions(+) create mode 100644 Public/Get-NCDeviceNotes.ps1 create mode 100644 Public/New-NCDeviceNote.ps1 create mode 100644 Public/Remove-NCDeviceNote.ps1 create mode 100644 Public/Set-NCDeviceNote.ps1 diff --git a/Public/Get-NCDeviceNotes.ps1 b/Public/Get-NCDeviceNotes.ps1 new file mode 100644 index 0000000..7b2e3fe --- /dev/null +++ b/Public/Get-NCDeviceNotes.ps1 @@ -0,0 +1,49 @@ +<# +.SYNOPSIS +Retrieves notes for a device. + +.DESCRIPTION +GET /api/devices/{deviceId}/notes. Supports pagination and pipeline input. + +.PARAMETER DeviceId +Target device. + +.EXAMPLE +Get-NCDeviceNotes -DeviceId 987 -All +#> +function Get-NCDeviceNotes { + [CmdletBinding(DefaultParameterSetName = 'Page')] + [OutputType([pscustomobject])] + param ( + [Parameter(Mandatory, ValueFromPipelineByPropertyName)] + [ValidateNotNullOrEmpty()] + [string]$DeviceId, + + [Parameter(ParameterSetName = 'All')] + [switch]$All, + + [Parameter(ParameterSetName = 'Page')] + [int]$PageNumber, + + [Parameter(ParameterSetName = 'Page')] + [int]$PageSize + ) + + begin { $api = Get-NCRestApiInstance } + + process { + $endpoint = "api/devices/$DeviceId/notes" + + if ($All) { + return Invoke-NCPagedRequest -Endpoint $endpoint + } + + $queryParameters = @{} + if ($PageNumber) { $queryParameters['pageNumber'] = $PageNumber } + if ($PageSize) { $queryParameters['pageSize'] = $PageSize } else { $queryParameters['pageSize'] = 500 } + + $endpoint += ConvertTo-NCQueryString -Parameters $queryParameters + Write-Verbose "[FUNCTION] Get-NCDeviceNotes: $endpoint" + $api.Get($endpoint) + } +} diff --git a/Public/New-NCDeviceNote.ps1 b/Public/New-NCDeviceNote.ps1 new file mode 100644 index 0000000..30df6a9 --- /dev/null +++ b/Public/New-NCDeviceNote.ps1 @@ -0,0 +1,74 @@ +<# +.SYNOPSIS +Adds a note to one or more devices. + +.DESCRIPTION +POST /api/devices/{deviceId}/notes for a single device, or +POST /api/devices/notes for multiple devices. + +.PARAMETER DeviceId +Single device to add the note to. Use -DeviceIds for multiple. + +.PARAMETER DeviceIds +Array of device IDs to add the note to (bulk endpoint). + +.PARAMETER UserId +The user ID associated with the note. + +.PARAMETER Note +The note text. + +.PARAMETER InsertionTime +Optional ISO 8601 timestamp for the note. + +.EXAMPLE +New-NCDeviceNote -DeviceId 987 -UserId 1 -Note 'Replaced hard drive' + +.EXAMPLE +New-NCDeviceNote -DeviceIds 100,200,300 -UserId 1 -Note 'Scheduled for maintenance' +#> +function New-NCDeviceNote { + [CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = 'Single')] + param ( + [Parameter(Mandatory, ParameterSetName = 'Single', ValueFromPipelineByPropertyName)] + [ValidateNotNullOrEmpty()] + [string]$DeviceId, + + [Parameter(Mandatory, ParameterSetName = 'Bulk')] + [object[]]$DeviceIds, + + [Parameter(Mandatory)] + [int]$UserId, + + [Parameter(Mandatory)] + [ValidateNotNullOrEmpty()] + [string]$Note, + + [string]$InsertionTime + ) + + begin { $api = Get-NCRestApiInstance } + + process { + if ($PSCmdlet.ParameterSetName -eq 'Bulk') { + Write-Verbose "[FUNCTION] New-NCDeviceNote: POST api/devices/notes (bulk)" + $body = @{ + deviceIds = $DeviceIds + userId = $UserId + note = $Note + } + if ($InsertionTime) { $body.insertionTime = $InsertionTime } + if (-not $PSCmdlet.ShouldProcess(($DeviceIds -join ','), 'Add note to devices')) { return } + return $api.Post('api/devices/notes', $body) + } + + Write-Verbose "[FUNCTION] New-NCDeviceNote: POST api/devices/$DeviceId/notes" + $body = @{ + userId = $UserId + note = $Note + } + if ($InsertionTime) { $body.insertionTime = $InsertionTime } + if (-not $PSCmdlet.ShouldProcess($DeviceId, 'Add note to device')) { return } + $api.Post("api/devices/$DeviceId/notes", $body) + } +} diff --git a/Public/Remove-NCDeviceNote.ps1 b/Public/Remove-NCDeviceNote.ps1 new file mode 100644 index 0000000..fc2d767 --- /dev/null +++ b/Public/Remove-NCDeviceNote.ps1 @@ -0,0 +1,61 @@ +<# +.SYNOPSIS +Deletes notes from a device. + +.DESCRIPTION +DELETE /api/devices/{deviceId}/notes/{noteId} for a single note, or +DELETE /api/devices/{deviceId}/notes with a body of noteIds for batch deletion. + +.PARAMETER DeviceId +Target device. + +.PARAMETER NoteId +Single note to delete. + +.PARAMETER NoteIds +Array of note IDs to delete in batch. + +.PARAMETER Force +Skip the confirmation prompt. + +.EXAMPLE +Remove-NCDeviceNote -DeviceId 987 -NoteId 'abc' -Force + +.EXAMPLE +Remove-NCDeviceNote -DeviceId 987 -NoteIds 'abc','def' +#> +function Remove-NCDeviceNote { + [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High', DefaultParameterSetName = 'Single')] + param ( + [Parameter(Mandatory, ValueFromPipelineByPropertyName)] + [ValidateNotNullOrEmpty()] + [string]$DeviceId, + + [Parameter(Mandatory, ParameterSetName = 'Single', ValueFromPipelineByPropertyName)] + [ValidateNotNullOrEmpty()] + [string]$NoteId, + + [Parameter(Mandatory, ParameterSetName = 'Batch')] + [object[]]$NoteIds, + + [switch]$Force + ) + + begin { $api = Get-NCRestApiInstance } + + process { + if ($PSCmdlet.ParameterSetName -eq 'Batch') { + $target = $NoteIds -join ',' + if ($Force -or $PSCmdlet.ShouldProcess($target, "Delete notes from device $DeviceId")) { + Write-Verbose "[FUNCTION] Remove-NCDeviceNote: DELETE api/devices/$DeviceId/notes (batch)" + $api.Delete("api/devices/$DeviceId/notes", @{ noteIds = $NoteIds }) + } + return + } + + if ($Force -or $PSCmdlet.ShouldProcess($NoteId, "Delete note from device $DeviceId")) { + Write-Verbose "[FUNCTION] Remove-NCDeviceNote: DELETE api/devices/$DeviceId/notes/$NoteId" + $api.Delete("api/devices/$DeviceId/notes/$NoteId") + } + } +} diff --git a/Public/Set-NCDeviceNote.ps1 b/Public/Set-NCDeviceNote.ps1 new file mode 100644 index 0000000..02dd67e --- /dev/null +++ b/Public/Set-NCDeviceNote.ps1 @@ -0,0 +1,43 @@ +<# +.SYNOPSIS +Modifies a note on a device. + +.DESCRIPTION +PUT /api/devices/{deviceId}/notes/{noteId}. + +.PARAMETER DeviceId +Target device. + +.PARAMETER NoteId +Note to modify. + +.PARAMETER Note +New note text. + +.EXAMPLE +Set-NCDeviceNote -DeviceId 987 -NoteId 'abc' -Note 'Updated text' +#> +function Set-NCDeviceNote { + [CmdletBinding(SupportsShouldProcess)] + param ( + [Parameter(Mandatory, ValueFromPipelineByPropertyName)] + [ValidateNotNullOrEmpty()] + [string]$DeviceId, + + [Parameter(Mandatory, ValueFromPipelineByPropertyName)] + [ValidateNotNullOrEmpty()] + [string]$NoteId, + + [Parameter(Mandatory)] + [ValidateNotNullOrEmpty()] + [string]$Note + ) + + begin { $api = Get-NCRestApiInstance } + + process { + Write-Verbose "[FUNCTION] Set-NCDeviceNote: PUT api/devices/$DeviceId/notes/$NoteId" + if (-not $PSCmdlet.ShouldProcess("$DeviceId/$NoteId", 'Modify device note')) { return } + $api.Put("api/devices/$DeviceId/notes/$NoteId", @{ note = $Note }) + } +} From de48a6bd0cf1de02af612044daab69e8bdf8c304 Mon Sep 17 00:00:00 2001 From: soybigmac Date: Mon, 31 Aug 2026 00:02:41 -0400 Subject: [PATCH 02/10] feat: add Custom PSA ticket lifecycle (4 endpoints) - New-NCCustomPsaTicket: create tickets (POST /custom-psa/tickets) - Get-NCCustomPsaTicket: now supports GET (no credentials) and POST variants - Invoke-NCCustomPsaTicket: reopen/resolve tickets --- Public/Get-NCCustomPsaTicket.ps1 | 24 +++++++++------ Public/Invoke-NCCustomPsaTicket.ps1 | 44 +++++++++++++++++++++++++++ Public/New-NCCustomPsaTicket.ps1 | 47 +++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 9 deletions(-) create mode 100644 Public/Invoke-NCCustomPsaTicket.ps1 create mode 100644 Public/New-NCCustomPsaTicket.ps1 diff --git a/Public/Get-NCCustomPsaTicket.ps1 b/Public/Get-NCCustomPsaTicket.ps1 index 7954f37..353653b 100644 --- a/Public/Get-NCCustomPsaTicket.ps1 +++ b/Public/Get-NCCustomPsaTicket.ps1 @@ -3,14 +3,17 @@ Retrieves details for a specific Custom-PSA ticket. .DESCRIPTION -POST /api/custom-psa/tickets/{customPsaTicketId}. The spec defines this as POST with a -PSA credential body. +GET /api/custom-psa/tickets/{customPsaTicketId} returns the ticket without credentials. +Supply -Credential to use the POST variant which authenticates against the PSA integration. .PARAMETER CustomPsaTicketId Ticket ID. .PARAMETER Credential -PSCredential containing username and password for the PSA integration. +Optional PSCredential for the PSA integration. When omitted, the credential-free GET endpoint is used. + +.EXAMPLE +Get-NCCustomPsaTicket -CustomPsaTicketId 'TKT-42' .EXAMPLE Get-NCCustomPsaTicket -CustomPsaTicketId 'TKT-42' -Credential (Get-Credential) @@ -23,16 +26,19 @@ function Get-NCCustomPsaTicket { [ValidateNotNullOrEmpty()] [string]$CustomPsaTicketId, - [Parameter(Mandatory)] [pscredential]$Credential ) begin { $api = Get-NCRestApiInstance } process { - Write-Verbose "[FUNCTION] Get-NCCustomPsaTicket: invoked." - $body = @{ - username = $Credential.UserName - password = $Credential.GetNetworkCredential().Password + if ($Credential) { + Write-Verbose "[FUNCTION] Get-NCCustomPsaTicket: POST api/custom-psa/tickets/$CustomPsaTicketId" + $body = @{ + username = $Credential.UserName + password = $Credential.GetNetworkCredential().Password + } + return $api.Post("api/custom-psa/tickets/$CustomPsaTicketId", $body) } - $api.Post("api/custom-psa/tickets/$CustomPsaTicketId", $body) + Write-Verbose "[FUNCTION] Get-NCCustomPsaTicket: GET api/custom-psa/tickets/$CustomPsaTicketId" + $api.Get("api/custom-psa/tickets/$CustomPsaTicketId") } } diff --git a/Public/Invoke-NCCustomPsaTicket.ps1 b/Public/Invoke-NCCustomPsaTicket.ps1 new file mode 100644 index 0000000..093ba4f --- /dev/null +++ b/Public/Invoke-NCCustomPsaTicket.ps1 @@ -0,0 +1,44 @@ +<# +.SYNOPSIS +Reopens or resolves a Custom PSA Ticket in N-central. + +.DESCRIPTION +POST /api/custom-psa/tickets/{id}/reopen or /resolve. + +.PARAMETER CustomPsaTicketId +Ticket ID. + +.PARAMETER Action +Action to perform: Reopen or Resolve. + +.EXAMPLE +Invoke-NCCustomPsaTicket -CustomPsaTicketId 'TKT-42' -Action Reopen + +.EXAMPLE +Invoke-NCCustomPsaTicket -CustomPsaTicketId 'TKT-42' -Action Resolve +#> +function Invoke-NCCustomPsaTicket { + [CmdletBinding(SupportsShouldProcess)] + param ( + [Parameter(Mandatory, ValueFromPipelineByPropertyName)] + [ValidateNotNullOrEmpty()] + [string]$CustomPsaTicketId, + + [Parameter(Mandatory)] + [ValidateSet('Reopen', 'Resolve')] + [string]$Action + ) + + begin { $api = Get-NCRestApiInstance } + + process { + $endpoint = if ($Action -eq 'Reopen') { + "api/custom-psa/tickets/$CustomPsaTicketId/reopen" + } else { + "api/custom-psa/tickets/$CustomPsaTicketId/resolve" + } + Write-Verbose "[FUNCTION] Invoke-NCCustomPsaTicket: POST $endpoint" + if (-not $PSCmdlet.ShouldProcess($CustomPsaTicketId, "$Action custom PSA ticket")) { return } + $api.Post($endpoint, @{}) + } +} diff --git a/Public/New-NCCustomPsaTicket.ps1 b/Public/New-NCCustomPsaTicket.ps1 new file mode 100644 index 0000000..48375f4 --- /dev/null +++ b/Public/New-NCCustomPsaTicket.ps1 @@ -0,0 +1,47 @@ +<# +.SYNOPSIS +Creates a Custom PSA Ticket in N-central. + +.DESCRIPTION +POST /api/custom-psa/tickets. + +.PARAMETER PsaCustomTicketId +The PSA custom ticket ID. + +.PARAMETER TicketNumber +The ticket number string. + +.PARAMETER TicketUrl +The URL to the ticket in the PSA system. + +.EXAMPLE +New-NCCustomPsaTicket -PsaCustomTicketId 42 -TicketNumber 'TKT-100' -TicketUrl 'https://psa.example.com/tickets/100' +#> +function New-NCCustomPsaTicket { + [CmdletBinding(SupportsShouldProcess)] + param ( + [Parameter(Mandatory)] + [int]$PsaCustomTicketId, + + [Parameter(Mandatory)] + [ValidateNotNullOrEmpty()] + [string]$TicketNumber, + + [Parameter(Mandatory)] + [ValidateNotNullOrEmpty()] + [string]$TicketUrl + ) + + begin { $api = Get-NCRestApiInstance } + + process { + Write-Verbose "[FUNCTION] New-NCCustomPsaTicket: invoked." + $body = @{ + psaCustomTicketId = $PsaCustomTicketId + ticketNumber = $TicketNumber + ticketUrl = $TicketUrl + } + if (-not $PSCmdlet.ShouldProcess($TicketNumber, 'Create custom PSA ticket')) { return } + $api.Post('api/custom-psa/tickets', $body) + } +} From 955c247fccf9d3bf8243cbc9ca2cf3767a8c576e Mon Sep 17 00:00:00 2001 From: soybigmac Date: Mon, 31 Aug 2026 00:02:50 -0400 Subject: [PATCH 03/10] feat: add Standard PSA company/contact/site endpoints and mapping update - Set-NCStandardPsaCustomerMapping: PUT customer mappings - Get-NCStandardPsaCompanies: list PSA companies - Get-NCStandardPsaContacts: list PSA contacts - Get-NCStandardPsaSites: list PSA sites --- Public/Get-NCStandardPsaCompanies.ps1 | 27 ++++++++++++ Public/Get-NCStandardPsaContacts.ps1 | 34 +++++++++++++++ Public/Get-NCStandardPsaSites.ps1 | 34 +++++++++++++++ Public/Set-NCStandardPsaCustomerMapping.ps1 | 46 +++++++++++++++++++++ 4 files changed, 141 insertions(+) create mode 100644 Public/Get-NCStandardPsaCompanies.ps1 create mode 100644 Public/Get-NCStandardPsaContacts.ps1 create mode 100644 Public/Get-NCStandardPsaSites.ps1 create mode 100644 Public/Set-NCStandardPsaCustomerMapping.ps1 diff --git a/Public/Get-NCStandardPsaCompanies.ps1 b/Public/Get-NCStandardPsaCompanies.ps1 new file mode 100644 index 0000000..725964e --- /dev/null +++ b/Public/Get-NCStandardPsaCompanies.ps1 @@ -0,0 +1,27 @@ +<# +.SYNOPSIS +Retrieves PSA companies for a customer. + +.DESCRIPTION +GET /api/standard-psa/customers/{customerId}/companies. + +.PARAMETER CustomerId +Customer ID. + +.EXAMPLE +Get-NCStandardPsaCompanies -CustomerId 100 +#> +function Get-NCStandardPsaCompanies { + [CmdletBinding()] + [OutputType([pscustomobject])] + param ( + [Parameter(Mandatory, ValueFromPipelineByPropertyName)] + [ValidateNotNullOrEmpty()] + [int]$CustomerId + ) + begin { $api = Get-NCRestApiInstance } + process { + Write-Verbose "[FUNCTION] Get-NCStandardPsaCompanies: api/standard-psa/customers/$CustomerId/companies" + $api.Get("api/standard-psa/customers/$CustomerId/companies") + } +} diff --git a/Public/Get-NCStandardPsaContacts.ps1 b/Public/Get-NCStandardPsaContacts.ps1 new file mode 100644 index 0000000..6e0b5a8 --- /dev/null +++ b/Public/Get-NCStandardPsaContacts.ps1 @@ -0,0 +1,34 @@ +<# +.SYNOPSIS +Retrieves PSA contacts for a customer and PSA company. + +.DESCRIPTION +GET /api/standard-psa/customers/{customerId}/companies/{psaCompanyId}/contacts. + +.PARAMETER CustomerId +Customer ID. + +.PARAMETER PsaCompanyId +PSA company ID. + +.EXAMPLE +Get-NCStandardPsaContacts -CustomerId 100 -PsaCompanyId 5 +#> +function Get-NCStandardPsaContacts { + [CmdletBinding()] + [OutputType([pscustomobject])] + param ( + [Parameter(Mandatory, ValueFromPipelineByPropertyName)] + [ValidateNotNullOrEmpty()] + [int]$CustomerId, + + [Parameter(Mandatory, ValueFromPipelineByPropertyName)] + [ValidateNotNullOrEmpty()] + [int]$PsaCompanyId + ) + begin { $api = Get-NCRestApiInstance } + process { + Write-Verbose "[FUNCTION] Get-NCStandardPsaContacts: api/standard-psa/customers/$CustomerId/companies/$PsaCompanyId/contacts" + $api.Get("api/standard-psa/customers/$CustomerId/companies/$PsaCompanyId/contacts") + } +} diff --git a/Public/Get-NCStandardPsaSites.ps1 b/Public/Get-NCStandardPsaSites.ps1 new file mode 100644 index 0000000..733163d --- /dev/null +++ b/Public/Get-NCStandardPsaSites.ps1 @@ -0,0 +1,34 @@ +<# +.SYNOPSIS +Retrieves PSA sites for a customer and PSA company. + +.DESCRIPTION +GET /api/standard-psa/customers/{customerId}/companies/{psaCompanyId}/sites. + +.PARAMETER CustomerId +Customer ID. + +.PARAMETER PsaCompanyId +PSA company ID. + +.EXAMPLE +Get-NCStandardPsaSites -CustomerId 100 -PsaCompanyId 5 +#> +function Get-NCStandardPsaSites { + [CmdletBinding()] + [OutputType([pscustomobject])] + param ( + [Parameter(Mandatory, ValueFromPipelineByPropertyName)] + [ValidateNotNullOrEmpty()] + [int]$CustomerId, + + [Parameter(Mandatory, ValueFromPipelineByPropertyName)] + [ValidateNotNullOrEmpty()] + [int]$PsaCompanyId + ) + begin { $api = Get-NCRestApiInstance } + process { + Write-Verbose "[FUNCTION] Get-NCStandardPsaSites: api/standard-psa/customers/$CustomerId/companies/$PsaCompanyId/sites" + $api.Get("api/standard-psa/customers/$CustomerId/companies/$PsaCompanyId/sites") + } +} diff --git a/Public/Set-NCStandardPsaCustomerMapping.ps1 b/Public/Set-NCStandardPsaCustomerMapping.ps1 new file mode 100644 index 0000000..7f8f653 --- /dev/null +++ b/Public/Set-NCStandardPsaCustomerMapping.ps1 @@ -0,0 +1,46 @@ +<# +.SYNOPSIS +Updates standard-PSA customer mappings. + +.DESCRIPTION +PUT /api/standard-psa/customer/{customerId}/mappings. + +.PARAMETER CustomerId +Customer ID. + +.PARAMETER PsaCompanyId +PSA company ID to map. + +.PARAMETER PsaSiteId +Optional PSA site ID. + +.PARAMETER PsaContactId +Optional PSA contact ID. + +.EXAMPLE +Set-NCStandardPsaCustomerMapping -CustomerId 100 -PsaCompanyId 5 +#> +function Set-NCStandardPsaCustomerMapping { + [CmdletBinding(SupportsShouldProcess)] + param ( + [Parameter(Mandatory, ValueFromPipelineByPropertyName)] + [ValidateNotNullOrEmpty()] + [int]$CustomerId, + + [int]$PsaCompanyId, + [int]$PsaSiteId, + [int]$PsaContactId + ) + + begin { $api = Get-NCRestApiInstance } + + process { + Write-Verbose "[FUNCTION] Set-NCStandardPsaCustomerMapping: PUT api/standard-psa/customer/$CustomerId/mappings" + $body = @{ customerId = $CustomerId } + if ($PSBoundParameters.ContainsKey('PsaCompanyId')) { $body.psaCompanyId = $PsaCompanyId } + if ($PSBoundParameters.ContainsKey('PsaSiteId')) { $body.psaSiteId = $PsaSiteId } + if ($PSBoundParameters.ContainsKey('PsaContactId')) { $body.psaContactId = $PsaContactId } + if (-not $PSCmdlet.ShouldProcess($CustomerId, 'Update standard PSA customer mapping')) { return } + $api.Put("api/standard-psa/customer/$CustomerId/mappings", $body) + } +} From a0c135eb86df31e351eb9a582f2ec735171b62e7 Mon Sep 17 00:00:00 2001 From: soybigmac Date: Mon, 31 Aug 2026 00:02:58 -0400 Subject: [PATCH 04/10] feat: add current user, org limits, remote control, user creation, and service actions - Get-NCCurrentUser: GET /api/users/me - Get-NCOrgLimits / Set-NCOrgLimits: get/patch org unit limits - New-NCRemoteControlTask / Get-NCRemoteControlType: remote control endpoints - New-NCUser: create user in org unit - Invoke-NCDeviceServiceAction: Windows service start/stop/restart --- Public/Get-NCCurrentUser.ps1 | 19 +++ Public/Get-NCOrgLimits.ps1 | 27 +++++ Public/Get-NCRemoteControlType.ps1 | 27 +++++ Public/Invoke-NCDeviceServiceAction.ps1 | 46 ++++++++ Public/New-NCRemoteControlTask.ps1 | 46 ++++++++ Public/New-NCUser.ps1 | 148 ++++++++++++++++++++++++ Public/Set-NCOrgLimits.ps1 | 34 ++++++ 7 files changed, 347 insertions(+) create mode 100644 Public/Get-NCCurrentUser.ps1 create mode 100644 Public/Get-NCOrgLimits.ps1 create mode 100644 Public/Get-NCRemoteControlType.ps1 create mode 100644 Public/Invoke-NCDeviceServiceAction.ps1 create mode 100644 Public/New-NCRemoteControlTask.ps1 create mode 100644 Public/New-NCUser.ps1 create mode 100644 Public/Set-NCOrgLimits.ps1 diff --git a/Public/Get-NCCurrentUser.ps1 b/Public/Get-NCCurrentUser.ps1 new file mode 100644 index 0000000..35226c2 --- /dev/null +++ b/Public/Get-NCCurrentUser.ps1 @@ -0,0 +1,19 @@ +<# +.SYNOPSIS +Retrieves the current authenticated user's information. + +.DESCRIPTION +GET /api/users/me. + +.EXAMPLE +Get-NCCurrentUser +#> +function Get-NCCurrentUser { + [CmdletBinding()] + [OutputType([pscustomobject])] + param () + + Write-Verbose "[FUNCTION] Get-NCCurrentUser: api/users/me" + $api = Get-NCRestApiInstance + $api.Get('api/users/me') +} diff --git a/Public/Get-NCOrgLimits.ps1 b/Public/Get-NCOrgLimits.ps1 new file mode 100644 index 0000000..49180c8 --- /dev/null +++ b/Public/Get-NCOrgLimits.ps1 @@ -0,0 +1,27 @@ +<# +.SYNOPSIS +Retrieves customer limits for an organization unit. + +.DESCRIPTION +GET /api/org-units/{orgUnitId}/limits. + +.PARAMETER OrgUnitId +Organization unit ID. + +.EXAMPLE +Get-NCOrgLimits -OrgUnitId 123 +#> +function Get-NCOrgLimits { + [CmdletBinding()] + [OutputType([pscustomobject])] + param ( + [Parameter(Mandatory, ValueFromPipelineByPropertyName)] + [ValidateNotNullOrEmpty()] + [int]$OrgUnitId + ) + begin { $api = Get-NCRestApiInstance } + process { + Write-Verbose "[FUNCTION] Get-NCOrgLimits: api/org-units/$OrgUnitId/limits" + $api.Get("api/org-units/$OrgUnitId/limits") + } +} diff --git a/Public/Get-NCRemoteControlType.ps1 b/Public/Get-NCRemoteControlType.ps1 new file mode 100644 index 0000000..ed72d70 --- /dev/null +++ b/Public/Get-NCRemoteControlType.ps1 @@ -0,0 +1,27 @@ +<# +.SYNOPSIS +Retrieves the remote-control configuration for a device. + +.DESCRIPTION +GET /api/devices/{deviceId}/remote-control-type. + +.PARAMETER DeviceId +Target device. + +.EXAMPLE +Get-NCRemoteControlType -DeviceId 987 +#> +function Get-NCRemoteControlType { + [CmdletBinding()] + [OutputType([pscustomobject])] + param ( + [Parameter(Mandatory, ValueFromPipelineByPropertyName)] + [ValidateNotNullOrEmpty()] + [int]$DeviceId + ) + begin { $api = Get-NCRestApiInstance } + process { + Write-Verbose "[FUNCTION] Get-NCRemoteControlType: api/devices/$DeviceId/remote-control-type" + $api.Get("api/devices/$DeviceId/remote-control-type") + } +} diff --git a/Public/Invoke-NCDeviceServiceAction.ps1 b/Public/Invoke-NCDeviceServiceAction.ps1 new file mode 100644 index 0000000..aa41db0 --- /dev/null +++ b/Public/Invoke-NCDeviceServiceAction.ps1 @@ -0,0 +1,46 @@ +<# +.SYNOPSIS +Performs an action on Windows Services for a device. + +.DESCRIPTION +POST /api/devices/{deviceId}/services/actions. + +.PARAMETER DeviceId +Target device. + +.PARAMETER ServiceNames +Array of Windows service names to act on. + +.PARAMETER Action +Action to perform (e.g. Start, Stop, Restart). + +.EXAMPLE +Invoke-NCDeviceServiceAction -DeviceId 987 -ServiceNames 'Spooler' -Action 'Restart' +#> +function Invoke-NCDeviceServiceAction { + [CmdletBinding(SupportsShouldProcess)] + param ( + [Parameter(Mandatory, ValueFromPipelineByPropertyName)] + [ValidateNotNullOrEmpty()] + [int]$DeviceId, + + [Parameter(Mandatory)] + [string[]]$ServiceNames, + + [Parameter(Mandatory)] + [ValidateNotNullOrEmpty()] + [string]$Action + ) + + begin { $api = Get-NCRestApiInstance } + + process { + Write-Verbose "[FUNCTION] Invoke-NCDeviceServiceAction: POST api/devices/$DeviceId/services/actions" + $body = @{ + serviceNames = $ServiceNames + action = $Action + } + if (-not $PSCmdlet.ShouldProcess("$($ServiceNames -join ',') on $DeviceId", "$Action Windows service(s)")) { return } + $api.Post("api/devices/$DeviceId/services/actions", $body) + } +} diff --git a/Public/New-NCRemoteControlTask.ps1 b/Public/New-NCRemoteControlTask.ps1 new file mode 100644 index 0000000..ea5ae2f --- /dev/null +++ b/Public/New-NCRemoteControlTask.ps1 @@ -0,0 +1,46 @@ +<# +.SYNOPSIS +Creates a remote-control task for a device. + +.DESCRIPTION +POST /api/devices/{deviceId}/remote-control-task. + +.PARAMETER DeviceId +Target device. + +.PARAMETER RemoteControlType +Remote control type string. + +.PARAMETER Description +Optional description. + +.PARAMETER Port +Optional port number. + +.EXAMPLE +New-NCRemoteControlTask -DeviceId 987 -RemoteControlType 'RDP' +#> +function New-NCRemoteControlTask { + [CmdletBinding(SupportsShouldProcess)] + param ( + [Parameter(Mandatory, ValueFromPipelineByPropertyName)] + [ValidateNotNullOrEmpty()] + [int]$DeviceId, + + [string]$RemoteControlType, + [string]$Description, + [int]$Port + ) + + begin { $api = Get-NCRestApiInstance } + + process { + Write-Verbose "[FUNCTION] New-NCRemoteControlTask: POST api/devices/$DeviceId/remote-control-task" + $body = @{} + if ($RemoteControlType) { $body.remoteControlType = $RemoteControlType } + if ($Description) { $body.description = $Description } + if ($PSBoundParameters.ContainsKey('Port')) { $body.port = $Port } + if (-not $PSCmdlet.ShouldProcess($DeviceId, 'Create remote control task')) { return } + $api.Post("api/devices/$DeviceId/remote-control-task", $body) + } +} diff --git a/Public/New-NCUser.ps1 b/Public/New-NCUser.ps1 new file mode 100644 index 0000000..f329e1f --- /dev/null +++ b/Public/New-NCUser.ps1 @@ -0,0 +1,148 @@ +<# +.SYNOPSIS +Creates a new user in the specified organization unit. + +.DESCRIPTION +POST /api/org-units/{orgUnitId}/users with the UserCreateRequest schema. + +.PARAMETER OrgUnitId +Org unit to create the user in. + +.PARAMETER Email +User email address (required). + +.PARAMETER Password +User password (required). Accepts [securestring] or [string]. + +.PARAMETER FirstName +User first name (required). + +.PARAMETER LastName +User last name (required). + +.PARAMETER Username +Optional username (defaults to email if omitted by the API). + +.PARAMETER Country +Optional country. + +.PARAMETER PostalCode +Optional postal code. + +.PARAMETER Street1 +Optional primary street address. + +.PARAMETER Street2 +Optional secondary street address. + +.PARAMETER City +Optional city. + +.PARAMETER State +Optional state. + +.PARAMETER Telephone +Optional telephone number. + +.PARAMETER Ext +Optional phone extension. + +.PARAMETER Department +Optional department. + +.PARAMETER NotificationEmail +Optional notification email. + +.PARAMETER Status +Optional user status. + +.PARAMETER RoleIds +Optional array of role IDs to assign. + +.PARAMETER AccessGroupIds +Optional array of access group IDs to assign. + +.PARAMETER ApiOnlyUser +If set, creates an API-only user. + +.EXAMPLE +New-NCUser -OrgUnitId 1 -Email 'user@example.com' -Password (Read-Host -AsSecureString) ` + -FirstName 'Jane' -LastName 'Doe' +#> +function New-NCUser { + [CmdletBinding(SupportsShouldProcess)] + param ( + [Parameter(Mandatory, ValueFromPipelineByPropertyName)] + [ValidateNotNullOrEmpty()] + [string]$OrgUnitId, + + [Parameter(Mandatory)] + [ValidateNotNullOrEmpty()] + [string]$Email, + + [Parameter(Mandatory)] + [object]$Password, + + [Parameter(Mandatory)] + [ValidateNotNullOrEmpty()] + [string]$FirstName, + + [Parameter(Mandatory)] + [ValidateNotNullOrEmpty()] + [string]$LastName, + + [string]$Username, + [string]$Country, + [string]$PostalCode, + [string]$Street1, + [string]$Street2, + [string]$City, + [string]$State, + [string]$Telephone, + [string]$Ext, + [string]$Department, + [string]$NotificationEmail, + [string]$Status, + [object[]]$RoleIds, + [object[]]$AccessGroupIds, + [switch]$ApiOnlyUser + ) + + begin { $api = Get-NCRestApiInstance } + + process { + Write-Verbose "[FUNCTION] New-NCUser: POST api/org-units/$OrgUnitId/users" + + $plainPassword = if ($Password -is [securestring]) { + $bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password) + try { [Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr) } + finally { [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr) } + } else { [string]$Password } + + $body = [ordered]@{ + email = $Email + password = $plainPassword + firstName = $FirstName + lastName = $LastName + } + + if ($Username) { $body.username = $Username } + if ($Country) { $body.country = $Country } + if ($PostalCode) { $body.postalCode = $PostalCode } + if ($Street1) { $body.street1 = $Street1 } + if ($Street2) { $body.street2 = $Street2 } + if ($City) { $body.city = $City } + if ($State) { $body.state = $State } + if ($Telephone) { $body.telephone = $Telephone } + if ($Ext) { $body.ext = $Ext } + if ($Department) { $body.department = $Department } + if ($NotificationEmail) { $body.notificationEmail = $NotificationEmail } + if ($Status) { $body.status = $Status } + if ($RoleIds) { $body.roleIds = $RoleIds } + if ($AccessGroupIds) { $body.accessGroupIds = $AccessGroupIds } + if ($ApiOnlyUser) { $body.apiOnlyUser = $true } + + if (-not $PSCmdlet.ShouldProcess($Email, 'Create user')) { return } + $api.Post("api/org-units/$OrgUnitId/users", $body) + } +} diff --git a/Public/Set-NCOrgLimits.ps1 b/Public/Set-NCOrgLimits.ps1 new file mode 100644 index 0000000..5d7e00e --- /dev/null +++ b/Public/Set-NCOrgLimits.ps1 @@ -0,0 +1,34 @@ +<# +.SYNOPSIS +Updates customer limits for an organization unit. + +.DESCRIPTION +PATCH /api/org-units/{orgUnitId}/limits. Only bound parameters are sent. + +.PARAMETER OrgUnitId +Organization unit ID. + +.PARAMETER Limits +Hashtable of limit key/value pairs to update. Keys and structure depend on the +N-central server version. + +.EXAMPLE +Set-NCOrgLimits -OrgUnitId 123 -Limits @{ maxDevices = 500 } +#> +function Set-NCOrgLimits { + [CmdletBinding(SupportsShouldProcess)] + param ( + [Parameter(Mandatory, ValueFromPipelineByPropertyName)] + [ValidateNotNullOrEmpty()] + [int]$OrgUnitId, + + [Parameter(Mandatory)] + [hashtable]$Limits + ) + begin { $api = Get-NCRestApiInstance } + process { + Write-Verbose "[FUNCTION] Set-NCOrgLimits: PATCH api/org-units/$OrgUnitId/limits" + if (-not $PSCmdlet.ShouldProcess($OrgUnitId, 'Update org unit limits')) { return } + $api.Patch("api/org-units/$OrgUnitId/limits", $Limits) + } +} From d2450a591297b2d80e5f1b9f75c79f2bcc9f2073 Mon Sep 17 00:00:00 2001 From: soybigmac Date: Mon, 31 Aug 2026 00:03:06 -0400 Subject: [PATCH 05/10] feat: add -Time to Get-NCServerInfo, expand Get-NCApiLinks, update manifest - Get-NCServerInfo -Time: GET /api/server-info/time - Get-NCApiLinks: add -AccessGroups, -ScheduledTasks, -Users switches - NCRestAPI.psd1: add 18 new functions to FunctionsToExport --- NCRestAPI.psd1 | 17 +++++++++++++++++ Public/Get-NCApiLinks.ps1 | 13 +++++++++++-- Public/Get-NCServerInfo.ps1 | 5 ++++- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/NCRestAPI.psd1 b/NCRestAPI.psd1 index 592df45..2f1a8af 100644 --- a/NCRestAPI.psd1 +++ b/NCRestAPI.psd1 @@ -74,6 +74,7 @@ 'Get-NCActiveIssues', 'Get-NCApplianceTask', 'Get-NCAssetLifecycle', + 'Get-NCCurrentUser', 'Get-NCCustomers', 'Get-NCCustomPsaTicket', 'Get-NCDefaultDeviceProperty', @@ -81,15 +82,18 @@ 'Get-NCDeviceActivationKey', 'Get-NCDeviceAssets', 'Get-NCDeviceMaintenanceWindows', + 'Get-NCDeviceNotes', 'Get-NCDeviceProperty', 'Get-NCDeviceScheduledTasks', 'Get-NCDeviceServices', 'Get-NCDevices', 'Get-NCFilters', 'Get-NCJobStatus', + 'Get-NCOrgLimits', 'Get-NCOrgProperty', 'Get-NCOrgUnits', 'Get-NCRegTokens', + 'Get-NCRemoteControlType', 'Get-NCReport', 'Get-NCRestApiInfo', 'Get-NCRestData', @@ -99,28 +103,41 @@ 'Get-NCServiceOrgs', 'Get-NCSites', 'Get-NCSoftwareInstallers', + 'Get-NCStandardPsaCompanies', + 'Get-NCStandardPsaContacts', 'Get-NCStandardPsaCustomerMapping', + 'Get-NCStandardPsaSites', 'Get-NCUserRoles', 'Get-NCUsers', + 'Invoke-NCCustomPsaTicket', + 'Invoke-NCDeviceServiceAction', 'New-NCCustomer', + 'New-NCCustomPsaTicket', 'New-NCDevice', 'New-NCDeviceAccessGroup', + 'New-NCDeviceNote', 'New-NCMaintenanceWindows', 'New-NCOrgAccessGroup', 'New-NCPatchComparisonReport', + 'New-NCRemoteControlTask', 'New-NCScheduledTask', 'New-NCServiceOrg', 'New-NCSite', 'New-NCSoftwareDownloadLink', + 'New-NCUser', 'New-NCUserRole', 'Remove-NCDevice', + 'Remove-NCDeviceNote', 'Remove-NCMaintenanceWindows', 'Set-NCAssetLifecycle', 'Set-NCDefaultOrgProperty', + 'Set-NCDeviceNote', 'Set-NCDeviceProperty', 'Set-NCMaintenanceWindows', + 'Set-NCOrgLimits', 'Set-NCOrgProperty', 'Set-NCRestConfig', + 'Set-NCStandardPsaCustomerMapping', 'Test-NCStandardPsaCredential', 'Update-NCAssetLifecycle' ) diff --git a/Public/Get-NCApiLinks.ps1 b/Public/Get-NCApiLinks.ps1 index 44a7c71..d32c096 100644 --- a/Public/Get-NCApiLinks.ps1 +++ b/Public/Get-NCApiLinks.ps1 @@ -3,12 +3,15 @@ Returns the list of discoverable endpoints under one of the root hypermedia nodes. .DESCRIPTION -Covers three `_links` navigation endpoints: +Covers six `_links` navigation endpoints: - default -> GET /api (top-level endpoint catalogue) + - -AccessGroups -> GET /api/access-groups - -CustomPsa -> GET /api/custom-psa - -CustomPsaTickets -> GET /api/custom-psa/tickets + - -ScheduledTasks -> GET /api/scheduled-tasks - -StandardPsa -> GET /api/standard-psa + - -Users -> GET /api/users Prefer `Get-NCServerInfo` for root `/api` metadata. This cmdlet exists so the module has explicit coverage for every spec endpoint. @@ -24,17 +27,23 @@ function Get-NCApiLinks { [OutputType([pscustomobject])] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '', Justification = 'Parameters are discriminators consumed via ParameterSetName.')] param ( + [Parameter(ParameterSetName = 'AccessGroups')][switch]$AccessGroups, [Parameter(ParameterSetName = 'CustomPsa')][switch]$CustomPsa, [Parameter(ParameterSetName = 'CustomPsaTickets')][switch]$CustomPsaTickets, - [Parameter(ParameterSetName = 'StandardPsa')][switch]$StandardPsa + [Parameter(ParameterSetName = 'ScheduledTasks')][switch]$ScheduledTasks, + [Parameter(ParameterSetName = 'StandardPsa')][switch]$StandardPsa, + [Parameter(ParameterSetName = 'Users')][switch]$Users ) Write-Verbose "[FUNCTION] Get-NCApiLinks: invoked." $api = Get-NCRestApiInstance $endpoint = switch ($PSCmdlet.ParameterSetName) { + 'AccessGroups' { 'api/access-groups' } 'CustomPsa' { 'api/custom-psa' } 'CustomPsaTickets' { 'api/custom-psa/tickets' } + 'ScheduledTasks' { 'api/scheduled-tasks' } 'StandardPsa' { 'api/standard-psa' } + 'Users' { 'api/users' } default { 'api' } } $api.Get($endpoint) diff --git a/Public/Get-NCServerInfo.ps1 b/Public/Get-NCServerInfo.ps1 index 6d3e2f1..5db9ee7 100644 --- a/Public/Get-NCServerInfo.ps1 +++ b/Public/Get-NCServerInfo.ps1 @@ -3,11 +3,12 @@ Retrieves N-central API service metadata. .DESCRIPTION -Covers four of the `/api` metadata endpoints: +Covers five of the `/api` metadata endpoints: - default -> GET /api - link list of top-level endpoints - -Version -> GET /api/server-info - running API-Service version - -Health -> GET /api/health - health status + - -Time -> GET /api/server-info/time - server time - -Extra -> GET /api/server-info/extra - extra version info (public) Supply `-Credential` together with `-Extra` to use the authenticated variant at @@ -30,6 +31,7 @@ function Get-NCServerInfo { param ( [Parameter(ParameterSetName = 'Health')][switch]$Health, [Parameter(ParameterSetName = 'Version')][switch]$Version, + [Parameter(ParameterSetName = 'Time')][switch]$Time, [Parameter(ParameterSetName = 'Extra')][switch]$Extra, [Parameter(ParameterSetName = 'Extra')][pscredential]$Credential ) @@ -40,6 +42,7 @@ function Get-NCServerInfo { switch ($PSCmdlet.ParameterSetName) { 'Health' { return $api.Get('api/health') } 'Version' { return $api.Get('api/server-info') } + 'Time' { return $api.Get('api/server-info/time') } 'Extra' { if ($Credential) { $body = @{ From 4ad7b53c22564b8ffeda922a2a2a6f99c53353c6 Mon Sep 17 00:00:00 2001 From: soybigmac Date: Mon, 31 Aug 2026 00:08:27 -0400 Subject: [PATCH 06/10] feat: add SSO authentication support (POST /api/auth/sso) - NCRestAPI class: add AuthenticateSso() method and UseSso flag - SSO constructor overload uses /api/auth/sso instead of /api/auth/authenticate - EnsureValidToken and RefreshAccessToken respect SSO mode for re-auth - Set-NCRestConfig: add -SsoToken parameter set - Connect-NCentral: add -SsoToken parameter set --- Private/NCRestAPI.ps1 | 42 +++++++++++++++++++++++++++++++++++-- Public/Connect-NCentral.ps1 | 17 ++++++++++----- Public/Set-NCRestConfig.ps1 | 33 +++++++++++++++++++---------- 3 files changed, 74 insertions(+), 18 deletions(-) diff --git a/Private/NCRestAPI.ps1 b/Private/NCRestAPI.ps1 index d7ea003..815a65a 100644 --- a/Private/NCRestAPI.ps1 +++ b/Private/NCRestAPI.ps1 @@ -26,6 +26,7 @@ class NCRestAPI { # big -All pulls or pipeline fan-out against rate-limited tenants. [int]$ThrottleMs = 0 [bool]$Verbose + hidden [bool]$UseSso = $false hidden [bool]$InPager = $false hidden [datetime]$LastRequestAt = [datetime]::MinValue @@ -38,6 +39,16 @@ class NCRestAPI { $this.Authenticate() } + NCRestAPI([string]$baseUrl, [securestring]$ssoToken, [string]$accessTokenExpiration, [string]$refreshTokenExpiration, [bool]$verbose, [bool]$useSso) { + $this.BaseUrl = $baseUrl + $this.ApiToken = $ssoToken + $this.AccessTokenExpiration = $accessTokenExpiration + $this.RefreshTokenExpiration = $refreshTokenExpiration + $this.Verbose = $verbose + $this.UseSso = $useSso + if ($useSso) { $this.AuthenticateSso() } else { $this.Authenticate() } + } + static [securestring] ToSecureString([string]$plain) { $s = New-Object System.Security.SecureString foreach ($c in $plain.ToCharArray()) { $s.AppendChar($c) } @@ -93,6 +104,30 @@ class NCRestAPI { $this.Log("[NCRESTAPI] Authenticate: succeeded.") } + [void] AuthenticateSso() { + $this.Log("[NCRESTAPI] AuthenticateSso: starting.") + $url = "$($this.BaseUrl)/api/auth/sso" + $headers = @{ + 'Accept' = '*/*' + 'Authorization' = "Bearer $($this.Reveal($this.ApiToken))" + } + if ($this.RefreshTokenExpiration) { $headers['X-REFRESH-EXPIRY-OVERRIDE'] = $this.RefreshTokenExpiration } + if ($this.AccessTokenExpiration) { $headers['X-ACCESS-EXPIRY-OVERRIDE'] = $this.AccessTokenExpiration } + + try { + $response = Invoke-RestMethod -Uri $url -Headers $headers -Method Post -TimeoutSec $this.TimeoutSec + } catch { + $this.Log("[NCRESTAPI] AuthenticateSso: failed: $($_.Exception.Message)") + throw "[NCRESTAPI] SSO authentication failed: $($_.Exception.Message)" + } + if (-not $response.tokens.access.token -or -not $response.tokens.refresh.token) { + throw "[NCRESTAPI] AuthenticateSso: response missing tokens." + } + $this.AccessToken = [NCRestAPI]::ToSecureString($response.tokens.access.token) + $this.RefreshToken = [NCRestAPI]::ToSecureString($response.tokens.refresh.token) + $this.Log("[NCRESTAPI] AuthenticateSso: succeeded.") + } + [bool] ValidateToken() { if (-not $this.AccessToken) { return $false } $url = "$($this.BaseUrl)/api/auth/validate" @@ -119,7 +154,7 @@ class NCRestAPI { $response = Invoke-RestMethod -Uri $url -Headers $headers -Method Post -Body $refreshPlain -TimeoutSec $this.TimeoutSec } catch { $this.Log("[NCRESTAPI] RefreshAccessToken: $($_.Exception.Message). Re-authenticating.") - $this.Authenticate() + if ($this.UseSso) { $this.AuthenticateSso() } else { $this.Authenticate() } return } if (-not $response.tokens.access.token) { @@ -132,7 +167,10 @@ class NCRestAPI { } [void] EnsureValidToken() { - if (-not $this.AccessToken) { $this.Authenticate(); return } + if (-not $this.AccessToken) { + if ($this.UseSso) { $this.AuthenticateSso() } else { $this.Authenticate() } + return + } if (-not $this.ValidateToken()) { $this.RefreshAccessToken() } } diff --git a/Public/Connect-NCentral.ps1 b/Public/Connect-NCentral.ps1 index 1cfa965..7f8b464 100644 --- a/Public/Connect-NCentral.ps1 +++ b/Public/Connect-NCentral.ps1 @@ -4,6 +4,7 @@ Establishes a connection to an N-central server. .DESCRIPTION Wrapper around Set-NCRestConfig that follows the PowerShell Connect-* convention. +Supports both API token and SSO token authentication. .PARAMETER BaseUrl Fully-qualified URL of the N-central server (https:// scheme added if omitted). @@ -11,6 +12,9 @@ Fully-qualified URL of the N-central server (https:// scheme added if omitted). .PARAMETER ApiToken User-level API token. Accepts [string] or [securestring]. +.PARAMETER SsoToken +SSO access token from an external identity provider. Accepts [string] or [securestring]. + .PARAMETER AccessTokenExpiration Override access-token lifetime (e.g. '1h', '120s'). Default '1h'. @@ -18,27 +22,30 @@ Override access-token lifetime (e.g. '1h', '120s'). Default '1h'. Override refresh-token lifetime (e.g. '25h'). Default '25h'. .PARAMETER PassThru -Emit the connection info object after authenticating - useful in scripts that want to -confirm the connect succeeded without a follow-up call. +Emit the connection info object after authenticating. .EXAMPLE Connect-NCentral -BaseUrl 'n-central.example.com' -ApiToken $token .EXAMPLE -$conn = Connect-NCentral -BaseUrl 'n-central.example.com' -ApiToken $token -PassThru +Connect-NCentral -BaseUrl 'n-central.example.com' -SsoToken $ssoToken -PassThru #> function Connect-NCentral { - [CmdletBinding()] + [CmdletBinding(DefaultParameterSetName = 'ApiToken')] [OutputType([pscustomobject])] param ( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$BaseUrl, - [Parameter(Mandatory)] + [Parameter(Mandatory, ParameterSetName = 'ApiToken')] [ValidateNotNullOrEmpty()] [object]$ApiToken, + [Parameter(Mandatory, ParameterSetName = 'SsoToken')] + [ValidateNotNullOrEmpty()] + [object]$SsoToken, + [ValidatePattern('^\d+[smh]$')] [string]$AccessTokenExpiration = '1h', diff --git a/Public/Set-NCRestConfig.ps1 b/Public/Set-NCRestConfig.ps1 index 81b9435..530fbb3 100644 --- a/Public/Set-NCRestConfig.ps1 +++ b/Public/Set-NCRestConfig.ps1 @@ -3,8 +3,8 @@ Configures the NCRestAPI module and establishes a connection to the N-central server. .DESCRIPTION -Stores the base URL, API token, and optional token-expiration overrides, then authenticates -and caches a module-scoped NCRestAPI instance that subsequent cmdlets reuse. +Stores the base URL, API token (or SSO token), and optional token-expiration overrides, +then authenticates and caches a module-scoped NCRestAPI instance that subsequent cmdlets reuse. .PARAMETER BaseUrl Fully-qualified URL of the N-central server (https:// scheme added if omitted). @@ -12,6 +12,10 @@ Fully-qualified URL of the N-central server (https:// scheme added if omitted). .PARAMETER ApiToken User-level API token from N-central. Accepts [string] or [securestring]. +.PARAMETER SsoToken +SSO access token from an external identity provider. Accepts [string] or [securestring]. +Uses POST /api/auth/sso instead of /api/auth/authenticate. + .PARAMETER AccessTokenExpiration Access-token lifetime override (e.g. '120s', '30m', '1h'). Default '1h'. @@ -39,15 +43,18 @@ Set-NCRestConfig -BaseUrl ... -ApiToken ... -ThrottleMs 200 -MaxRetries 5 Author: Zach Frazier #> function Set-NCRestConfig { - [CmdletBinding()] + [CmdletBinding(DefaultParameterSetName = 'ApiToken')] param ( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$BaseUrl, - [Parameter(Mandatory)] + [Parameter(Mandatory, ParameterSetName = 'ApiToken')] [object]$ApiToken, + [Parameter(Mandatory, ParameterSetName = 'SsoToken')] + [object]$SsoToken, + [ValidatePattern('^\d+[smh]$')] [string]$AccessTokenExpiration = '1h', @@ -67,16 +74,20 @@ function Set-NCRestConfig { if ($BaseUrl -notmatch '^https?://') { $BaseUrl = 'https://' + $BaseUrl } $BaseUrl = $BaseUrl.TrimEnd('/') - if ($ApiToken -is [securestring]) { - $secureApiToken = $ApiToken - } elseif ($ApiToken -is [string]) { - $secureApiToken = [NCRestAPI]::ToSecureString($ApiToken) + $useSso = $PSCmdlet.ParameterSetName -eq 'SsoToken' + $rawToken = if ($useSso) { $SsoToken } else { $ApiToken } + + if ($rawToken -is [securestring]) { + $secureToken = $rawToken + } elseif ($rawToken -is [string]) { + $secureToken = [NCRestAPI]::ToSecureString($rawToken) } else { - throw "ApiToken must be [string] or [securestring]." + throw "Token must be [string] or [securestring]." } - Write-Verbose "[NCRESTCONFIG] Creating NCRestAPI instance for $BaseUrl." - $instance = [NCRestAPI]::new($BaseUrl, $secureApiToken, $AccessTokenExpiration, $RefreshTokenExpiration, ($VerbosePreference -eq 'Continue')) + $authLabel = if ($useSso) { 'SSO' } else { 'API token' } + Write-Verbose "[NCRESTCONFIG] Creating NCRestAPI instance for $BaseUrl ($authLabel)." + $instance = [NCRestAPI]::new($BaseUrl, $secureToken, $AccessTokenExpiration, $RefreshTokenExpiration, ($VerbosePreference -eq 'Continue'), $useSso) $instance.TimeoutSec = $TimeoutSec $instance.MaxRetries = $MaxRetries $instance.ThrottleMs = $ThrottleMs From 53f94084bc83423684e4b967bc2a6a5176acb944 Mon Sep 17 00:00:00 2001 From: soybigmac Date: Mon, 31 Aug 2026 00:09:14 -0400 Subject: [PATCH 07/10] chore: bump version to 1.9.0, add changelog for API coverage gaps --- CHANGELOG.md | 22 ++++++++++++++++++++++ NCRestAPI.psd1 | 2 +- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aad4619..a52588b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,27 @@ # Changelog +## 1.9.0 + +### Added + +- **Device Notes**: `Get-NCDeviceNotes`, `New-NCDeviceNote`, `Set-NCDeviceNote`, + `Remove-NCDeviceNote` — full CRUD for device notes including bulk operations. +- **Custom PSA Tickets**: `New-NCCustomPsaTicket` (create), `Invoke-NCCustomPsaTicket` + (reopen/resolve). `Get-NCCustomPsaTicket` now supports the credential-free `GET` + variant in addition to the existing `POST`. +- **Standard PSA**: `Set-NCStandardPsaCustomerMapping` (update mappings), + `Get-NCStandardPsaCompanies`, `Get-NCStandardPsaContacts`, `Get-NCStandardPsaSites`. +- **Remote Control**: `New-NCRemoteControlTask`, `Get-NCRemoteControlType`. +- **Org Unit Limits**: `Get-NCOrgLimits`, `Set-NCOrgLimits`. +- **User Management**: `New-NCUser` (create user in org unit), + `Get-NCCurrentUser` (`GET /api/users/me`). +- **Windows Services**: `Invoke-NCDeviceServiceAction` (start/stop/restart). +- **SSO Authentication**: `Connect-NCentral -SsoToken` and `Set-NCRestConfig -SsoToken` + for identity-provider-based authentication via `POST /api/auth/sso`. +- `Get-NCServerInfo -Time`: `GET /api/server-info/time`. +- `Get-NCApiLinks`: added `-AccessGroups`, `-ScheduledTasks`, `-Users` switches + for the remaining navigation endpoints. + ## 1.8.1 ### Fixed diff --git a/NCRestAPI.psd1 b/NCRestAPI.psd1 index 2f1a8af..8ccc679 100644 --- a/NCRestAPI.psd1 +++ b/NCRestAPI.psd1 @@ -9,7 +9,7 @@ RootModule = 'NCRestAPI.psm1' # Version number of this module. - ModuleVersion = '1.8.1' + ModuleVersion = '1.9.0' # Supported PSEditions CompatiblePSEditions = @('Desktop', 'Core') From 58a9f3de08333cadab1592d1ce3bd26cec8666dc Mon Sep 17 00:00:00 2001 From: soybigmac Date: Mon, 31 Aug 2026 00:09:57 -0400 Subject: [PATCH 08/10] docs: update README with new functions and SSO support --- README.md | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 74dd68a..cd52807 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ Handles authentication, token refresh, pagination, and retries so you can focus ## Features - Token-based authentication with automatic refresh (`/api/auth/authenticate`, `/api/auth/refresh`) +- SSO authentication via external identity providers (`/api/auth/sso`) - Tokens held in memory as `SecureString` — never written to disk or environment - Unified request path with automatic retry on 429 / 5xx, 60 s timeout, and URL-encoded query strings - Verbose logging scrubs JWTs from output @@ -30,6 +31,9 @@ Connect-NCentral -BaseUrl 'n-central.example.com' -ApiToken $env:NC_API_TOKEN # Or Set-NCRestConfig (same thing, older name) Set-NCRestConfig -BaseUrl 'n-central.example.com' -ApiToken $env:NC_API_TOKEN +# SSO authentication (external identity provider) +Connect-NCentral -BaseUrl 'n-central.example.com' -SsoToken $ssoAccessToken + # Use Get-NCDevices -OrgUnitId 42 -All # auto-paginates Get-NCDevices -DeviceId 987654321 # single device @@ -54,7 +58,7 @@ Connect-NCentral -BaseUrl ... -ApiToken ... -AccessTokenExpiration '15m' -Refres | Command | Endpoint(s) | | --- | --- | -| `Connect-NCentral` / `Set-NCRestConfig` | `/api/auth/authenticate` | +| `Connect-NCentral` / `Set-NCRestConfig` | `/api/auth/authenticate`, `/api/auth/sso` | | `Disconnect-NCentral` / `Get-NCRestApiInfo -Kill` | — | | `Get-NCDevices` | `/api/devices`, `/api/devices/{id}`, `/api/org-units/{id}/devices` | | `Get-NCCustomers` | `/api/customers`, `/api/customers/{id}`, `/api/service-orgs/{id}/customers` | @@ -68,13 +72,16 @@ Connect-NCentral -BaseUrl ... -ApiToken ... -AccessTokenExpiration '15m' -Refres | `Get-NCDeviceScheduledTasks` | `/api/devices/{id}/scheduled-tasks` | | `Get-NCDeviceActivationKey` | `/api/devices/{id}/activation-key` | | `Get-NCDeviceMaintenanceWindows` | `GET /api/devices/{id}/maintenance-windows` | +| `Get-NCDeviceNotes` / `New-NCDeviceNote` / `Set-NCDeviceNote` / `Remove-NCDeviceNote` | Device notes CRUD at `/api/devices/{id}/notes[/{noteId}]`, `/api/devices/notes` | | `New-NCMaintenanceWindows` / `Set-NCMaintenanceWindows` / `Remove-NCMaintenanceWindows` | Maintenance-window CRUD at `/api/devices/maintenance-windows` | | `Get-NCAssetLifecycle` / `Set-NCAssetLifecycle` / `Update-NCAssetLifecycle` | `/api/devices/{id}/assets/lifecycle-info` (GET / PUT / PATCH) | | `New-NCDevice` | `POST /api/device` (device enrollment) | | `Remove-NCDevice` | `DELETE /api/devices/{id}` (supports `-WhatIf`/`-Confirm`) | | `Get-NCSoftwareInstallers` / `New-NCSoftwareDownloadLink` | `/api/customers/{id}/software/installers` | | `Get-NCReport` / `New-NCPatchComparisonReport` | `/api/report/...` | -| `Get-NCStandardPsaCustomerMapping` / `Test-NCStandardPsaCredential` / `Get-NCCustomPsaTicket` | PSA integrations (`/api/standard-psa`, `/api/custom-psa`) | +| `Get-NCStandardPsaCustomerMapping` / `Set-NCStandardPsaCustomerMapping` / `Test-NCStandardPsaCredential` / `Get-NCCustomPsaTicket` | PSA integrations (`/api/standard-psa`, `/api/custom-psa`) | +| `Get-NCStandardPsaCompanies` / `Get-NCStandardPsaContacts` / `Get-NCStandardPsaSites` | Standard PSA company/contact/site lookups | +| `New-NCCustomPsaTicket` / `Invoke-NCCustomPsaTicket` | Custom PSA ticket create / reopen / resolve | | `Get-NCDeviceProperty` / `Set-NCDeviceProperty` | `/api/devices/{id}/custom-properties[/{propId}]` | | `Get-NCOrgProperty` / `Set-NCOrgProperty` | `/api/org-units/{id}/custom-properties[/{propId}]` | | `Get-NCDefaultOrgProperty` / `Set-NCDefaultOrgProperty` | `/api/org-units/{id}/org-custom-property-defaults[/{propId}]` | @@ -85,12 +92,16 @@ Connect-NCentral -BaseUrl ... -ApiToken ... -AccessTokenExpiration '15m' -Refres | `Get-NCScheduledTasks` / `Get-NCScheduledTaskStatus` | `/api/scheduled-tasks/...` | | `New-NCScheduledTask` | `POST /api/scheduled-tasks/direct` | | `Get-NCRegTokens` | `/api/{customers,sites,org-units}/{id}/registration-token` | -| `Get-NCServerInfo` | `/api`, `/api/server-info`, `/api/server-info/extra`, `/api/health` | -| `Get-NCUsers` / `Get-NCUserRoles` / `New-NCUserRole` | `/api/users`, `/api/org-units/{id}/users`, `.../user-roles` | +| `Get-NCServerInfo` | `/api`, `/api/server-info`, `/api/server-info/extra`, `/api/server-info/time`, `/api/health` | +| `Get-NCCurrentUser` | `/api/users/me` | +| `Get-NCOrgLimits` / `Set-NCOrgLimits` | `/api/org-units/{id}/limits` (GET / PATCH) | +| `New-NCRemoteControlTask` / `Get-NCRemoteControlType` | `/api/devices/{id}/remote-control-task`, `.../remote-control-type` | +| `Invoke-NCDeviceServiceAction` | `POST /api/devices/{id}/services/actions` | +| `Get-NCUsers` / `Get-NCUserRoles` / `New-NCUserRole` / `New-NCUser` | `/api/users`, `/api/org-units/{id}/users`, `.../user-roles` | | `New-NCCustomer` / `New-NCServiceOrg` / `New-NCSite` | Customer / SO / site creation | | `New-NCDeviceAccessGroup` / `New-NCOrgAccessGroup` | Access-group creation | | `Get-NCRestData` | Escape hatch for any endpoint not yet wrapped (`-Method Get/Post/Put/Patch/Delete`, `-Body`) | -| `Get-NCApiLinks` | Hypermedia `_links` at `/api`, `/api/custom-psa*`, `/api/standard-psa` | +| `Get-NCApiLinks` | Hypermedia `_links` at `/api`, `/api/access-groups`, `/api/custom-psa*`, `/api/scheduled-tasks`, `/api/standard-psa`, `/api/users` | Run `Get-Help -Examples` for usage on any command. From 239c0b7ab040cfb6855640c23e7632c6e535070c Mon Sep 17 00:00:00 2001 From: soybigmac Date: Mon, 31 Aug 2026 00:14:59 -0400 Subject: [PATCH 09/10] fix: New-NCUser Password param as securestring, suppress analyzer false positive --- Public/New-NCUser.ps1 | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/Public/New-NCUser.ps1 b/Public/New-NCUser.ps1 index f329e1f..1392a67 100644 --- a/Public/New-NCUser.ps1 +++ b/Public/New-NCUser.ps1 @@ -12,7 +12,7 @@ Org unit to create the user in. User email address (required). .PARAMETER Password -User password (required). Accepts [securestring] or [string]. +User password (required). Must be a [securestring]. .PARAMETER FirstName User first name (required). @@ -20,7 +20,7 @@ User first name (required). .PARAMETER LastName User last name (required). -.PARAMETER Username +.PARAMETER UserName Optional username (defaults to email if omitted by the API). .PARAMETER Country @@ -71,6 +71,7 @@ New-NCUser -OrgUnitId 1 -Email 'user@example.com' -Password (Read-Host -AsSecure #> function New-NCUser { [CmdletBinding(SupportsShouldProcess)] + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingUsernameAndPasswordParams', '', Justification = 'UserName is an optional display name, not a login credential paired with Password.')] param ( [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [ValidateNotNullOrEmpty()] @@ -81,7 +82,7 @@ function New-NCUser { [string]$Email, [Parameter(Mandatory)] - [object]$Password, + [securestring]$Password, [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] @@ -91,7 +92,7 @@ function New-NCUser { [ValidateNotNullOrEmpty()] [string]$LastName, - [string]$Username, + [string]$UserName, [string]$Country, [string]$PostalCode, [string]$Street1, @@ -113,11 +114,9 @@ function New-NCUser { process { Write-Verbose "[FUNCTION] New-NCUser: POST api/org-units/$OrgUnitId/users" - $plainPassword = if ($Password -is [securestring]) { - $bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password) - try { [Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr) } - finally { [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr) } - } else { [string]$Password } + $bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password) + try { $plainPassword = [Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr) } + finally { [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr) } $body = [ordered]@{ email = $Email @@ -126,7 +125,7 @@ function New-NCUser { lastName = $LastName } - if ($Username) { $body.username = $Username } + if ($UserName) { $body.username = $UserName } if ($Country) { $body.country = $Country } if ($PostalCode) { $body.postalCode = $PostalCode } if ($Street1) { $body.street1 = $Street1 } From 846e638a8c012f6b02a27111bb9885996549e4c3 Mon Sep 17 00:00:00 2001 From: soybigmac Date: Mon, 31 Aug 2026 00:19:42 -0400 Subject: [PATCH 10/10] fix: use [string] for all ID params, add Root param set to Get-NCApiLinks Address PR review: DeviceId/OrgUnitId/CustomerId/PsaCompanyId changed from [int] to [string] for consistency with existing module convention. Added explicit Root parameter set to Get-NCApiLinks. --- Public/Get-NCApiLinks.ps1 | 1 + Public/Get-NCOrgLimits.ps1 | 2 +- Public/Get-NCRemoteControlType.ps1 | 2 +- Public/Get-NCStandardPsaCompanies.ps1 | 2 +- Public/Get-NCStandardPsaContacts.ps1 | 4 ++-- Public/Get-NCStandardPsaSites.ps1 | 4 ++-- Public/Invoke-NCDeviceServiceAction.ps1 | 2 +- Public/New-NCRemoteControlTask.ps1 | 2 +- Public/Set-NCOrgLimits.ps1 | 2 +- Public/Set-NCStandardPsaCustomerMapping.ps1 | 2 +- 10 files changed, 12 insertions(+), 11 deletions(-) diff --git a/Public/Get-NCApiLinks.ps1 b/Public/Get-NCApiLinks.ps1 index d32c096..1ffb105 100644 --- a/Public/Get-NCApiLinks.ps1 +++ b/Public/Get-NCApiLinks.ps1 @@ -27,6 +27,7 @@ function Get-NCApiLinks { [OutputType([pscustomobject])] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '', Justification = 'Parameters are discriminators consumed via ParameterSetName.')] param ( + [Parameter(ParameterSetName = 'Root')][switch]$Root, [Parameter(ParameterSetName = 'AccessGroups')][switch]$AccessGroups, [Parameter(ParameterSetName = 'CustomPsa')][switch]$CustomPsa, [Parameter(ParameterSetName = 'CustomPsaTickets')][switch]$CustomPsaTickets, diff --git a/Public/Get-NCOrgLimits.ps1 b/Public/Get-NCOrgLimits.ps1 index 49180c8..4c4ed60 100644 --- a/Public/Get-NCOrgLimits.ps1 +++ b/Public/Get-NCOrgLimits.ps1 @@ -17,7 +17,7 @@ function Get-NCOrgLimits { param ( [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [ValidateNotNullOrEmpty()] - [int]$OrgUnitId + [string]$OrgUnitId ) begin { $api = Get-NCRestApiInstance } process { diff --git a/Public/Get-NCRemoteControlType.ps1 b/Public/Get-NCRemoteControlType.ps1 index ed72d70..3f4c44e 100644 --- a/Public/Get-NCRemoteControlType.ps1 +++ b/Public/Get-NCRemoteControlType.ps1 @@ -17,7 +17,7 @@ function Get-NCRemoteControlType { param ( [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [ValidateNotNullOrEmpty()] - [int]$DeviceId + [string]$DeviceId ) begin { $api = Get-NCRestApiInstance } process { diff --git a/Public/Get-NCStandardPsaCompanies.ps1 b/Public/Get-NCStandardPsaCompanies.ps1 index 725964e..d92d7ac 100644 --- a/Public/Get-NCStandardPsaCompanies.ps1 +++ b/Public/Get-NCStandardPsaCompanies.ps1 @@ -17,7 +17,7 @@ function Get-NCStandardPsaCompanies { param ( [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [ValidateNotNullOrEmpty()] - [int]$CustomerId + [string]$CustomerId ) begin { $api = Get-NCRestApiInstance } process { diff --git a/Public/Get-NCStandardPsaContacts.ps1 b/Public/Get-NCStandardPsaContacts.ps1 index 6e0b5a8..54c8839 100644 --- a/Public/Get-NCStandardPsaContacts.ps1 +++ b/Public/Get-NCStandardPsaContacts.ps1 @@ -20,11 +20,11 @@ function Get-NCStandardPsaContacts { param ( [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [ValidateNotNullOrEmpty()] - [int]$CustomerId, + [string]$CustomerId, [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [ValidateNotNullOrEmpty()] - [int]$PsaCompanyId + [string]$PsaCompanyId ) begin { $api = Get-NCRestApiInstance } process { diff --git a/Public/Get-NCStandardPsaSites.ps1 b/Public/Get-NCStandardPsaSites.ps1 index 733163d..4b3e6dd 100644 --- a/Public/Get-NCStandardPsaSites.ps1 +++ b/Public/Get-NCStandardPsaSites.ps1 @@ -20,11 +20,11 @@ function Get-NCStandardPsaSites { param ( [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [ValidateNotNullOrEmpty()] - [int]$CustomerId, + [string]$CustomerId, [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [ValidateNotNullOrEmpty()] - [int]$PsaCompanyId + [string]$PsaCompanyId ) begin { $api = Get-NCRestApiInstance } process { diff --git a/Public/Invoke-NCDeviceServiceAction.ps1 b/Public/Invoke-NCDeviceServiceAction.ps1 index aa41db0..737edb7 100644 --- a/Public/Invoke-NCDeviceServiceAction.ps1 +++ b/Public/Invoke-NCDeviceServiceAction.ps1 @@ -22,7 +22,7 @@ function Invoke-NCDeviceServiceAction { param ( [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [ValidateNotNullOrEmpty()] - [int]$DeviceId, + [string]$DeviceId, [Parameter(Mandatory)] [string[]]$ServiceNames, diff --git a/Public/New-NCRemoteControlTask.ps1 b/Public/New-NCRemoteControlTask.ps1 index ea5ae2f..752f293 100644 --- a/Public/New-NCRemoteControlTask.ps1 +++ b/Public/New-NCRemoteControlTask.ps1 @@ -25,7 +25,7 @@ function New-NCRemoteControlTask { param ( [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [ValidateNotNullOrEmpty()] - [int]$DeviceId, + [string]$DeviceId, [string]$RemoteControlType, [string]$Description, diff --git a/Public/Set-NCOrgLimits.ps1 b/Public/Set-NCOrgLimits.ps1 index 5d7e00e..dfb4a97 100644 --- a/Public/Set-NCOrgLimits.ps1 +++ b/Public/Set-NCOrgLimits.ps1 @@ -20,7 +20,7 @@ function Set-NCOrgLimits { param ( [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [ValidateNotNullOrEmpty()] - [int]$OrgUnitId, + [string]$OrgUnitId, [Parameter(Mandatory)] [hashtable]$Limits diff --git a/Public/Set-NCStandardPsaCustomerMapping.ps1 b/Public/Set-NCStandardPsaCustomerMapping.ps1 index 7f8f653..0ee0075 100644 --- a/Public/Set-NCStandardPsaCustomerMapping.ps1 +++ b/Public/Set-NCStandardPsaCustomerMapping.ps1 @@ -25,7 +25,7 @@ function Set-NCStandardPsaCustomerMapping { param ( [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [ValidateNotNullOrEmpty()] - [int]$CustomerId, + [string]$CustomerId, [int]$PsaCompanyId, [int]$PsaSiteId,