diff --git a/.vscode/.spelling b/.vscode/.spelling index 29218fb..5f8279c 100644 --- a/.vscode/.spelling +++ b/.vscode/.spelling @@ -3,6 +3,10 @@ TeamViewer TeamViewer's TeamViewerPS TVPS +Organizational Unit +Organizational Units +OrganizationalUnit +OrganizationalUnits // Powershell cmdlet diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c5a4ef..a0ec053 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ ### Added +- Adds `Get-TeamViewerOrganizationalUnit` to retrieve the organizational unit details (beta phase, available only for specific tenants). +- Adds `New-TeamViewerOrganizationalUnit` to add a new organizational unit (beta phase, available only for specific tenants). +- Adds `Remove-TeamViewerOrganizationalUnit` to delete the organizational unit (beta phase, available only for specific tenants). +- Adds `Set-TeamViewerOrganizationalUnit` to modify the organizational unit (beta phase, available only for specific tenants). - Adds `Get-TeamViewerRolePermission` to retrieve all supported role permissions. - Adds `Get-TeamViewerDeviceCustomField` to retrieve custom field values from a managed device. - Adds `Set-TeamViewerDeviceCustomField` to set or update a custom field value on a managed device. @@ -15,6 +19,7 @@ ### Changed +- Fixes, completes, and improves help file `TeamViewerPS.md`. - Adds `OutputType` to public commands. - Adds `CmdletBinding` to public commands. - Standardizes pipeline emission on Write-Output. diff --git a/Cmdlets/Private/ConvertTo-TeamViewerOrganizationalUnit.ps1 b/Cmdlets/Private/ConvertTo-TeamViewerOrganizationalUnit.ps1 new file mode 100644 index 0000000..4a20a56 --- /dev/null +++ b/Cmdlets/Private/ConvertTo-TeamViewerOrganizationalUnit.ps1 @@ -0,0 +1,24 @@ +function ConvertTo-TeamViewerOrganizationalUnit { + param( + [Parameter(ValueFromPipeline = $true, Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [PSObject] + $InputObject + ) + + process { + $properties = @{ + Id = $InputObject.id + Name = $InputObject.name + Description = $InputObject.description + ParentId = $InputObject.parentId + CreatedAt = $InputObject.createdAt + UpdatedAt = $InputObject.updatedAt + } + + $result = New-Object -TypeName PSObject -Property $properties + $result.PSObject.TypeNames.Insert(0, 'TeamViewerPS.OrganizationalUnit') + + Write-Output $result + } +} diff --git a/Cmdlets/Private/Resolve-TeamViewerOrganizationalUnitId.ps1 b/Cmdlets/Private/Resolve-TeamViewerOrganizationalUnitId.ps1 new file mode 100644 index 0000000..e0e9ddd --- /dev/null +++ b/Cmdlets/Private/Resolve-TeamViewerOrganizationalUnitId.ps1 @@ -0,0 +1,24 @@ +function Resolve-TeamViewerOrganizationalUnitId { + param( + [Parameter(ValueFromPipeline = $true, Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [PSObject] + $OrganizationalUnit + ) + + process { + if ($OrganizationalUnit.PSObject.TypeNames -contains 'TeamViewerPS.OrganizationalUnit') { + Write-Output $OrganizationalUnit.Id + } + elseif ($OrganizationalUnit -is [string]) { + if ($OrganizationalUnit -notmatch '(?im)^[{(]?[0-9A-F]{8}[-]?(?:[0-9A-F]{4}[-]?){3}[0-9A-F]{12}[)}]?$') { + throw "Invalid organizational unit identifier '$OrganizationalUnit'. String must be an UUID." + } + + $OrganizationalUnit + } + else { + throw "Invalid organizational unit identifier '$OrganizationalUnit'. Must be either a [TeamViewerPS.OrganizationalUnit] or [UUID]." + } + } +} diff --git a/Cmdlets/Public/Get-TeamViewerOrganizationalUnit.ps1 b/Cmdlets/Public/Get-TeamViewerOrganizationalUnit.ps1 new file mode 100644 index 0000000..4824d06 --- /dev/null +++ b/Cmdlets/Public/Get-TeamViewerOrganizationalUnit.ps1 @@ -0,0 +1,99 @@ +function Get-TeamViewerOrganizationalUnit { + [CmdletBinding(DefaultParameterSetName = 'List')] + + param( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [Alias('Token')] + [securestring] + $ApiToken, + + [Parameter(ValueFromPipeline = $true, Mandatory = $true, ParameterSetName = 'ById')] + [ValidateScript({ $_ | Resolve-TeamViewerOrganizationalUnitId })] + [Alias('Id', 'OrganizationalUnitId')] + [object] + $OrganizationalUnit, + + [Parameter( Mandatory = $false, ParameterSetName = 'List')] + [Alias('IncludeChildren')] + [Switch] + $Recursive, + + [Parameter( Mandatory = $false, ParameterSetName = 'List')] + [ValidateScript({ $_ -match '(?im)^[{(]?[0-9A-F]{8}[-]?(?:[0-9A-F]{4}[-]?){3}[0-9A-F]{12}[)}]?$' })] + [Alias('ParentId')] + [string] + $Parent, + + [Parameter( Mandatory = $false, ParameterSetName = 'List')] + [ValidateLength(1, [int]::MaxValue)] + [string] + $Filter, + + [Parameter( Mandatory = $false, ParameterSetName = 'List')] + [ValidateSet('Name', 'CreatedAt', 'UpdatedAt')] + [Alias('Sort')] + [string] + $SortBy = 'Name', + + [Parameter( Mandatory = $false, ParameterSetName = 'List')] + [ValidateSet('Asc', 'Desc')] + [Alias('Order')] + [string] + $SortOrder = 'Asc', + + [Parameter( Mandatory = $false, ParameterSetName = 'List')] + [ValidateRange(50, 250)] + [int] + $PageSize = 100, + + [Parameter( Mandatory = $false, ParameterSetName = 'List')] + [ValidateRange(1, [int]::MaxValue)] + [int] + $PageNumber = 1 + ) + + process { + $Uri = "$(Get-TeamViewerApiUri)/organizationalunits" + $Body = @{} + + switch ($PSCmdlet.ParameterSetName) { + 'ById' { + $OrganizationalUnitId = $OrganizationalUnit | Resolve-TeamViewerOrganizationalUnitId + $Uri += "/$OrganizationalUnitId" + $Body = $null + } + 'List' { + if ($Recursive) { + $Body.includeChildren = $true + } + if ($Parent) { + $Body.startOrganizationalUnitId = $Parent + } + if ($Filter) { + $Body.filter = $Filter + } + + $Body.sortBy = $SortBy + $Body.sortOrder = $SortOrder + $Body.pageSize = $PageSize + $Body.pageNumber = $PageNumber + } + } + + $Response = Invoke-TeamViewerRestMethod ` + -ApiToken $ApiToken ` + -Uri $Uri ` + -Method Get ` + -Body $Body ` + -WriteErrorTo $PSCmdlet ` + -ErrorAction Stop + + if ($PSCmdlet.ParameterSetName -eq 'ById') { + $Response | ConvertTo-TeamViewerOrganizationalUnit + } + else { + $Response.data | ConvertTo-TeamViewerOrganizationalUnit + } + } +} diff --git a/Cmdlets/Public/New-TeamViewerOrganizationalUnit.ps1 b/Cmdlets/Public/New-TeamViewerOrganizationalUnit.ps1 new file mode 100644 index 0000000..84e6f06 --- /dev/null +++ b/Cmdlets/Public/New-TeamViewerOrganizationalUnit.ps1 @@ -0,0 +1,56 @@ +function New-TeamViewerOrganizationalUnit { + [CmdletBinding(SupportsShouldProcess = $true)] + + param( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [Alias('Token')] + [securestring] + $ApiToken, + + [Parameter( Mandatory = $true)] + [ValidateLength(1, 100)] + [string] + $Name, + + [Parameter(Mandatory = $false)] + [ValidateLength(1, 300)] + [string] + $Description, + + [Parameter(Mandatory = $false)] + [ValidateScript({ $_ -match '(?im)^[{(]?[0-9A-F]{8}[-]?(?:[0-9A-F]{4}[-]?){3}[0-9A-F]{12}[)}]?$' })] + [Alias('ParentId')] + [string] + $Parent + ) + + begin { + $Uri = "$(Get-TeamViewerApiUri)/organizationalunits" + + # Append parameters to request body + $Body = @{ name = $Name } + + if ($Description) { + $Body.description = $Description + } + if ($Parent) { + $Body.parentId = $Parent + } + } + + process { + if ($PSCmdlet.ShouldProcess($Name, 'Create organizational unit')) { + $Response = Invoke-TeamViewerRestMethod ` + -ApiToken $ApiToken ` + -Uri $Uri ` + -Method Post ` + -ContentType 'application/json; charset=utf-8' ` + -Body ([System.Text.Encoding]::UTF8.GetBytes(($Body | ConvertTo-Json))) ` + -WriteErrorTo $PSCmdlet ` + -ErrorAction Stop + + $Response | ConvertTo-TeamViewerOrganizationalUnit + } + } +} diff --git a/Cmdlets/Public/Remove-TeamViewerOrganizationalUnit.ps1 b/Cmdlets/Public/Remove-TeamViewerOrganizationalUnit.ps1 new file mode 100644 index 0000000..38a6962 --- /dev/null +++ b/Cmdlets/Public/Remove-TeamViewerOrganizationalUnit.ps1 @@ -0,0 +1,31 @@ +function Remove-TeamViewerOrganizationalUnit { + [CmdletBinding(SupportsShouldProcess = $true)] + + param( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [Alias('Token')] + [securestring] + $ApiToken, + + [Parameter(ValueFromPipeline = $true, Mandatory = $true)] + [ValidateScript({ $_ | Resolve-TeamViewerOrganizationalUnitId })] + [Alias('Id', 'OrganizationalUnitId')] + [object] + $OrganizationalUnit + ) + + process { + $OrganizationalUnitId = $OrganizationalUnit | Resolve-TeamViewerOrganizationalUnitId + $Uri = "$(Get-TeamViewerApiUri)/organizationalunits/$OrganizationalUnitId" + + if ($PSCmdlet.ShouldProcess($OrganizationalUnitId, 'Remove organizational unit')) { + Invoke-TeamViewerRestMethod ` + -ApiToken $ApiToken ` + -Uri $Uri ` + -Method Delete ` + -WriteErrorTo $PSCmdlet ` + -ErrorAction Stop | Out-Null + } + } +} diff --git a/Cmdlets/Public/Set-TeamViewerOrganizationalUnit.ps1 b/Cmdlets/Public/Set-TeamViewerOrganizationalUnit.ps1 new file mode 100644 index 0000000..cfd5330 --- /dev/null +++ b/Cmdlets/Public/Set-TeamViewerOrganizationalUnit.ps1 @@ -0,0 +1,68 @@ +function Set-TeamViewerOrganizationalUnit { + [CmdletBinding(SupportsShouldProcess = $true)] + + param( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [Alias('Token')] + [securestring] + $ApiToken, + + [Parameter(ValueFromPipeline = $true, Mandatory = $true)] + [ValidateScript({ $_ | Resolve-TeamViewerOrganizationalUnitId })] + [Alias('Id', 'OrganizationalUnitId')] + [object] + $OrganizationalUnit, + + [Parameter(Mandatory = $false)] + [ValidateLength(1, 100)] + [string] + $Name, + + [Parameter(Mandatory = $false)] + [ValidateLength(1, 300)] + [string] + $Description, + + [Parameter(Mandatory = $false)] + [ValidateScript({ $_ -match '(?im)^[{(]?[0-9A-F]{8}[-]?(?:[0-9A-F]{4}[-]?){3}[0-9A-F]{12}[)}]?$' })] + [Alias('ParentId')] + [string] + $Parent + ) + + begin { + $Body = @{ } + + # Append parameters to request body + if ($Name) { + $Body.name = $Name + } + + if ($Description) { + $Body.description = $Description + } + + if ($Parent) { + $Body.parentId = $Parent + } + } + + process { + $OrganizationalUnitId = $OrganizationalUnit | Resolve-TeamViewerOrganizationalUnitId + $Uri = "$(Get-TeamViewerApiUri)/organizationalunits/$OrganizationalUnitId" + + if ($PSCmdlet.ShouldProcess($OrganizationalUnitId, 'Change organizational unit')) { + $response = Invoke-TeamViewerRestMethod ` + -ApiToken $ApiToken ` + -Uri $Uri ` + -Method Put ` + -ContentType 'application/json; charset=utf-8' ` + -Body ([System.Text.Encoding]::UTF8.GetBytes(($Body | ConvertTo-Json))) ` + -WriteErrorTo $PSCmdlet ` + -ErrorAction Stop + + $response | ConvertTo-TeamViewerOrganizationalUnit + } + } +} diff --git a/Docs/Help/Get-TeamViewerOrganizationalUnit.md b/Docs/Help/Get-TeamViewerOrganizationalUnit.md new file mode 100644 index 0000000..23d00e9 --- /dev/null +++ b/Docs/Help/Get-TeamViewerOrganizationalUnit.md @@ -0,0 +1,217 @@ +--- +external help file: TeamViewerPS-help.xml +Module Name: TeamViewerPS +online version: https://github.com/teamviewer/TeamViewerPS/blob/main/Docs/Help/Get-TeamViewerOrganizationalUnit.md +schema: 2.0.0 +--- + +# Get-TeamViewerOrganizationalUnit + +## SYNOPSIS + +Returns a single or multiple TeamViewer organizational units of the associated TeamViewer company. + +> [!NOTE] +> This command is in beta phase and available only for specific tenants. + +## SYNTAX + +### List (Default) + +```powershell +Get-TeamViewerOrganizationalUnit -ApiToken [-Recursive ] [-Parent ] [-Filter ] [-SortBy ] [-SortOrder ] [-PageSize ] [-PageNumber ][] +``` + +### ById + +```powershell +Get-TeamViewerOrganizationalUnit -ApiToken [-OrganizationalUnit ] [] +``` + +## EXAMPLES + +### Example 1 + +```powershell +PS /> Get-TeamViewerOrganizationalUnit +``` + +Lists all TeamViewer organizational units that are associated to the TV company. + +### Example 2 + +```powershell +PS /> Get-TeamViewerOrganizationalUnit -Id '1cbae0b5-8a2f-487a-a8cf-5b884787b52c' +``` + +Gets one specific TeamViewer organizational unit with the given Id `1cbae0b5-8a2f-487a-a8cf-5b884787b52c`. + +### Example 3 + +```powershell +PS /> Get-TeamViewerOrganizationalUnit -Filter 'test' +``` + +Lists all TeamViewer organizational units of the TV company that have the string `test` in their name or description. + +## PARAMETERS + +### -ApiToken + +The TeamViewer API access token. + +```yaml +Type: SecureString +Parameter Sets: (All) +Aliases: Token + +Required: True +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -OrganizationalUnit + +Object that can be used to identify the organizational unit. +This can either be the organizational unit Id or an organizational unit object +that has been received using other module functions. + +```yaml +Type: PSObject +Parameter Sets: ById +Aliases: Id, OrganizationalUnitId + +Required: True +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Recursive + +A breadth-first traversal through all levels of the organizational unit hierarchy. + +```yaml +Type: SwitchParameter +Parameter Sets: List +Aliases: IncludeChildren + +Required: False +Position: Named +Default value: False +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Parent + +Define the organizational unit where processing starts. If not set, the root OU will be used as starting point. + +```yaml +Type: String +Parameter Sets: List +Aliases: ParentId + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Filter + +Filter organizational units by name and description. + +```yaml +Type: String +Parameter Sets: List +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -SortBy + +Sort organizational units by Name, CreatedAt, or UpdatedAt field. + +```yaml +Type: String +Parameter Sets: List +Aliases: Sort + +Required: False +Position: Named +Default value: Name +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -SortOrder + +Sort direction of organizational units. + +```yaml +Type: String +Parameter Sets: List +Aliases: Order + +Required: False +Position: Named +Default value: Asc +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -PageSize + +The number of results per page. The default is 100. The minimum is 50, the maximum is 250. + +```yaml +Type: Integer +Parameter Sets: List +Aliases: + +Required: False +Position: Named +Default value: 100 +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -PageNumber + +The page number of results to retrieve. The first page is 1. + +```yaml +Type: Integer +Parameter Sets: List +Aliases: + +Required: False +Position: Named +Default value: 1 +Accept pipeline input: False +Accept wildcard characters: False +``` + +### CommonParameters + +This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). + +## INPUTS + +### None + +## OUTPUTS + +## NOTES + +## RELATED LINKS diff --git a/Docs/Help/New-TeamViewerOrganizationalUnit.md b/Docs/Help/New-TeamViewerOrganizationalUnit.md new file mode 100644 index 0000000..69e9633 --- /dev/null +++ b/Docs/Help/New-TeamViewerOrganizationalUnit.md @@ -0,0 +1,135 @@ +--- +external help file: TeamViewerPS-help.xml +Module Name: TeamViewerPS +online version: https://github.com/teamviewer/TeamViewerPS/blob/main/Docs/Help/New-TeamViewerOrganizationalUnit.md +schema: 2.0.0 +--- + +# New-TeamViewerOrganizationalUnit + +## SYNOPSIS + +Creates a TeamViewer organizational unit in the associated TeamViewer company. + +> [!NOTE] +> This command is in beta phase and available only for specific tenants. + +## SYNTAX + +```powershell +New-TeamViewerOrganizationalUnit [-ApiToken] [-Name] [-Description] [-Parent] [-Confirm] [-WhatIf] [] +``` + +## EXAMPLES + +### Example 1 + +```powershell +PS /> New-TeamViewerOrganizationalUnit -Name 'Test' +``` + +Creates a new organizational unit with the given name `Test` directly below the root organizational unit. + +### Example 2 + +```powershell +PS /> New-TeamViewerOrganizationalUnit -Name 'Test' -Description 'Test organizational unit' -Parent '1cbae0b5-8a2f-487a-a8cf-5b884787b52c' +``` + +Creates a new organizational unit with the given name `Test` with description below a specific organizational unit. + +## PARAMETERS + +### -ApiToken + +The TeamViewer API access token. + +```yaml +Type: SecureString +Parameter Sets: (All) +Aliases: Token + +Required: True +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Name + +The name of the new organizational unit. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: + +Required: True +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Description + +The description of the new organizational unit. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Parent + +Id of the parent organizational unit. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: ParentId + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -WhatIf + +Shows what would happen if the cmdlet runs. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### CommonParameters + +This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). + +## INPUTS + +### None + +## OUTPUTS + +## NOTES + +## RELATED LINKS diff --git a/Docs/Help/Remove-TeamViewerOrganizationalUnit.md b/Docs/Help/Remove-TeamViewerOrganizationalUnit.md new file mode 100644 index 0000000..1f2491d --- /dev/null +++ b/Docs/Help/Remove-TeamViewerOrganizationalUnit.md @@ -0,0 +1,113 @@ +--- +external help file: TeamViewerPS-help.xml +Module Name: TeamViewerPS +online version: https://github.com/teamviewer/TeamViewerPS/blob/main/Docs/Help/Remove-TeamViewerOrganizationalUnit.md +schema: 2.0.0 +--- + +# Remove-TeamViewerOrganizationalUnit + +## SYNOPSIS + +Deletes an organizational unit from the associated TeamViewer company. + +> [!NOTE] +> This command is in beta phase and available only for specific tenants. + +## SYNTAX + +```powershell +Remove-TeamViewerOrganizationalUnit [-ApiToken] [-OrganizationalUnit] [-Confirm] [-WhatIf] [] +``` + +## EXAMPLES + +### Example 1 + +```powershell +PS /> Remove-TeamViewerOrganizationalUnit -Id '1cbae0b5-8a2f-487a-a8cf-5b884787b52c' +``` + +Deletes one specific organizational unit with the given Id `1cbae0b5-8a2f-487a-a8cf-5b884787b52c` from the associated TeamViewer company. + +## PARAMETERS + +### -ApiToken + +The TeamViewer API access token. + +```yaml +Type: SecureString +Parameter Sets: (All) +Aliases: Token + +Required: True +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -OrganizationalUnit + +Object that can be used to identify the organizational unit. +This can either be the organizational unit Id or an organizational unit object +that has been received using other module functions. + +```yaml +Type: PSObject +Parameter Sets: +Aliases: Id, OrganizationalUnitId + +Required: True +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Confirm + +Prompts you for confirmation before running the cmdlet. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -WhatIf + +Shows what would happen if the cmdlet runs. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### CommonParameters + +This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). + +## INPUTS + +### System.Object + +## OUTPUTS + +## NOTES + +## RELATED LINKS diff --git a/Docs/Help/Set-TeamViewerOrganizationalUnit.md b/Docs/Help/Set-TeamViewerOrganizationalUnit.md new file mode 100644 index 0000000..e2d14b4 --- /dev/null +++ b/Docs/Help/Set-TeamViewerOrganizationalUnit.md @@ -0,0 +1,161 @@ +--- +external help file: TeamViewerPS-help.xml +Module Name: TeamViewerPS +online version: https://github.com/teamviewer/TeamViewerPS/blob/main/Docs/Help/Set-TeamViewerOrganizationalUnit.md +schema: 2.0.0 +--- + +# Set-TeamViewerOrganizationalUnit + +## SYNOPSIS + +Changes a TeamViewer organizational unit in the associated TeamViewer company. + +> [!NOTE] +> This command is in beta phase and available only for specific tenants. + +## SYNTAX + +```powershell +Set-TeamViewerOrganizationalUnit -ApiToken -OrganizationalUnit [-Name ] [-Description ] [-Parent ] [-Confirm] [-WhatIf] [] +``` + +## EXAMPLES + +### Example 1 + +```powershell +PS /> Set-TeamViewerOrganizationalUnit -OrganizationalUnit '1cbae0b5-8a2f-487a-a8cf-5b884787b52c' -Name 'New organizational unit name' +``` + +Changes the name of the organizational unit with the given Id `1cbae0b5-8a2f-487a-a8cf-5b884787b52c` to `New organizational unit name`. + +## PARAMETERS + +### -ApiToken + +The TeamViewer API access token. + +```yaml +Type: SecureString +Parameter Sets: (All) +Aliases: Token + +Required: True +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -OrganizationalUnit + +Object that can be used to identify the organizational unit. +This can either be the organizational unit Id or an organizational unit object +that has been received using other module functions. + +```yaml +Type: PSObject +Parameter Sets: +Aliases: Id, OrganizationalUnitId + +Required: True +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Name + +The name of the new organizational unit. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: + +Required: True +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Description + +The description of the new organizational unit. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Parent + +Id of the parent organizational unit. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: ParentId + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Confirm + +Prompts you for confirmation before running the cmdlet. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -WhatIf + +Shows what would happen if the cmdlet runs. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### CommonParameters + +This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). + +## INPUTS + +### System.Object + +## OUTPUTS + +## NOTES + +## RELATED LINKS diff --git a/Docs/TeamViewerPS.md b/Docs/TeamViewerPS.md index c0a17d6..2753428 100644 --- a/Docs/TeamViewerPS.md +++ b/Docs/TeamViewerPS.md @@ -38,6 +38,19 @@ Manage company / tenant details for the TeamViewer company associated with the A [`Set-TeamViewerCompany`](Help/Set-TeamViewerCompany.md) +## Organizational Units + +Manage organizational units of a TeamViewer company via the TeamViewer web API. +Have organizational units to further group / organize / structure users and user groups. + +[`Get-TeamViewerOrganizationalUnit`](Help/Get-TeamViewerOrganizationalUnit.md) + +[`New-TeamViewerOrganizationalUnit`](Help/New-TeamViewerOrganizationalUnit.md) + +[`Remove-TeamViewerOrganizationalUnit`](Help/Remove-TeamViewerOrganizationalUnit.md) + +[`Set-TeamViewerOrganizationalUnit`](Help/Set-TeamViewerOrganizationalUnit.md) + ## Computers & Contacts Manage the devices & contacts via the TeamViewer web API. diff --git a/Tests/Private/ConvertTo-TeamViewerOrganizationalUnit.Tests.ps1 b/Tests/Private/ConvertTo-TeamViewerOrganizationalUnit.Tests.ps1 new file mode 100644 index 0000000..a8d3584 --- /dev/null +++ b/Tests/Private/ConvertTo-TeamViewerOrganizationalUnit.Tests.ps1 @@ -0,0 +1,57 @@ +BeforeAll { + $Script:Module_RootPath = (Resolve-Path -Path (Join-Path -Path $PSScriptRoot -ChildPath '..\..')) + $Script:Module_PrivCmdletsPath = Join-Path -Path $Module_RootPath -ChildPath 'Cmdlets\Private' + + . (Join-Path -Path $Module_PrivCmdletsPath -ChildPath 'ConvertTo-TeamViewerOrganizationalUnit.ps1') +} + +Describe 'ConvertTo-TeamViewerOrganizationalUnit' { + It 'Returns an object for pipeline input' { + $InputObject = [pscustomobject]@{ + id = ([guid]::NewGuid().ToString()) + name = 'Sample' + description = 'A sample organizational unit' + parentId = ([guid]::NewGuid().ToString()) + createdAt = '2023-01-01T00:00:00Z' + updatedAt = '2023-01-02T00:00:00Z' + } + + $Result = $InputObject | & ConvertTo-TeamViewerOrganizationalUnit + + $Result | Should -Not -BeNullOrEmpty + $Result.PSObject.TypeNames[0] | Should -Be 'TeamViewerPS.OrganizationalUnit' + } + + It 'Maps the API fields to the object properties' { + $Id = [guid]::NewGuid().ToString() + $ParentId = [guid]::NewGuid().ToString() + $InputObject = [pscustomobject]@{ + id = $Id + name = 'Sample' + description = 'A sample organizational unit' + parentId = $ParentId + createdAt = '2023-01-01T00:00:00Z' + updatedAt = '2023-01-02T00:00:00Z' + } + + $Result = $InputObject | & ConvertTo-TeamViewerOrganizationalUnit + + $Result.Id | Should -Be $Id + $Result.Name | Should -Be 'Sample' + $Result.Description | Should -Be 'A sample organizational unit' + $Result.ParentId | Should -Be $ParentId + $Result.CreatedAt | Should -Be '2023-01-01T00:00:00Z' + $Result.UpdatedAt | Should -Be '2023-01-02T00:00:00Z' + } + + It 'Supports pipeline processing of multiple items' { + $InputObjects = @( + [pscustomobject]@{ id = ([guid]::NewGuid().ToString()); name = 'One' }, + [pscustomobject]@{ id = ([guid]::NewGuid().ToString()); name = 'Two' } + ) + + $Result = $InputObjects | & ConvertTo-TeamViewerOrganizationalUnit + + @($Result).Count | Should -Be 2 + } +} diff --git a/Tests/Private/Resolve-TeamViewerOrganizationalUnitId.Tests.ps1 b/Tests/Private/Resolve-TeamViewerOrganizationalUnitId.Tests.ps1 new file mode 100644 index 0000000..be1ce73 --- /dev/null +++ b/Tests/Private/Resolve-TeamViewerOrganizationalUnitId.Tests.ps1 @@ -0,0 +1,32 @@ +BeforeAll { + $Script:Module_RootPath = (Resolve-Path -Path (Join-Path -Path $PSScriptRoot -ChildPath '..\..')) + $Script:Module_PrivCmdletsPath = Join-Path -Path $Module_RootPath -ChildPath 'Cmdlets\Private' + + . (Join-Path -Path $Module_PrivCmdletsPath -ChildPath 'Resolve-TeamViewerOrganizationalUnitId.ps1') +} + +Describe 'Resolve-TeamViewerOrganizationalUnitId' { + It 'Returns guid from TeamViewerPS.OrganizationalUnit object' { + $Id = [guid]::NewGuid() + $OrganizationalUnit = [pscustomobject]@{ Id = $Id } + $OrganizationalUnit.PSObject.TypeNames.Insert(0, 'TeamViewerPS.OrganizationalUnit') + + Resolve-TeamViewerOrganizationalUnitId -OrganizationalUnit $OrganizationalUnit | Should -Be $Id + } + + It 'Returns guid string unchanged' { + $Id = [guid]::NewGuid() + + Resolve-TeamViewerOrganizationalUnitId -OrganizationalUnit $Id.ToString() | Should -Be $Id.ToString() + } + + It 'Throws for an invalid string identifier' { + { Resolve-TeamViewerOrganizationalUnitId -OrganizationalUnit 'not-a-uuid' } | ` + Should -Throw "Invalid organizational unit identifier 'not-a-uuid'. String must be an UUID." + } + + It 'Throws for an unsupported identifier type' { + { Resolve-TeamViewerOrganizationalUnitId -OrganizationalUnit 42 } | ` + Should -Throw "Invalid organizational unit identifier '42'. Must be either a ``[TeamViewerPS.OrganizationalUnit``] or ``[UUID``]." + } +} diff --git a/Tests/Public/Get-TeamViewerOrganizationalUnit.Tests.ps1 b/Tests/Public/Get-TeamViewerOrganizationalUnit.Tests.ps1 new file mode 100644 index 0000000..16be42a --- /dev/null +++ b/Tests/Public/Get-TeamViewerOrganizationalUnit.Tests.ps1 @@ -0,0 +1,102 @@ +BeforeAll { + . "$PSScriptRoot\..\..\Cmdlets\Public\Get-TeamViewerOrganizationalUnit.ps1" + + @(Get-ChildItem -Path "$PSScriptRoot\..\..\Cmdlets\Private\*.ps1") | ForEach-Object { . $_.FullName } + + $testApiToken = [securestring]@{} + $null = $testApiToken + $null = $example_uuid + $example_uuid = '7042bac2-7ce0-47c6-8c1a-fb00505bd6ed' + + Mock Get-TeamViewerApiUri { '//unit.test' } + Mock Invoke-TeamViewerRestMethod { @{ + data = @( + @{ + name = 'Root' + parentId = '' + id = 'd696ef85-d40a-479e-8331-4813f59e6481' + description = '' + createdAt = '24/03/2025 12:49:25' + updatedAt = '24/03/2025 12:49:25' + }, + @{ + name = 'TestOU2' + parentId = 'd696ef85-d40a-479e-8331-4813f59e6481' + id = '7042bac2-7ce0-47c6-8c1a-fb00505bd6ed' + description = '' + createdAt = '24/03/2025 13:30:38' + updatedAt = '24/03/2025 13:30:38' + }, + @{ + name = 'TestOUCMD' + parentId = 'd696ef85-d40a-479e-8331-4813f59e6481' + id = 'a400ad06-9c59-4a33-b110-4649fcce6f45' + description = '' + createdAt = '24/03/2025 13:43:02' + updatedAt = '24/03/2025 13:43:02' + } + ) + } } +} + +Describe 'Get-TeamViewerOrganizationalUnit' { + + It 'Should call the correct API endpoint to list users' { + Get-TeamViewerOrganizationalUnit -ApiToken $testApiToken + + Should -Invoke Invoke-TeamViewerRestMethod -Times 1 -Scope It -ParameterFilter { + $ApiToken -eq $testApiToken -and $Uri -eq '//unit.test/organizationalunits' -and $Method -eq 'Get' } + } + + It 'Should call the correct API endpoint for single ID' { + Get-TeamViewerOrganizationalUnit -ApiToken $testApiToken -Id $example_uuid + + Should -Invoke Invoke-TeamViewerRestMethod -Times 1 -Scope It -ParameterFilter { + $ApiToken -eq $testApiToken -and $Uri -eq '//unit.test/organizationalunits/' + $example_uuid -and $Method -eq 'Get' } + } + + It 'Should return Org unit objects' { + $result = Get-TeamViewerOrganizationalUnit -ApiToken $testApiToken + $result | Should -HaveCount 3 + $result[0].PSObject.TypeNames | Should -Contain 'TeamViewerPS.OrganizationalUnit' + } + + It 'Should allow to filter by name' { + Get-TeamViewerOrganizationalUnit -ApiToken $testApiToken -Filter 'Test' + + Should -Invoke Invoke-TeamViewerRestMethod -Times 1 -Scope It -ParameterFilter { + $Body -and $Body['filter'] -eq 'Test' } + } + + It 'Should allow to specification of IncludeChildren, StartOrganizationalUnitId, SortBy and Sort Order, Page Size and Page Number' { + Get-TeamViewerOrganizationalUnit -ApiToken $testApiToken -IncludeChildren -Parent $example_uuid -SortBy 'Name' -SortOrder 'Asc' -PageSize 200 -PageNumber 2 + + Should -Invoke Invoke-TeamViewerRestMethod -Times 1 -Scope It -ParameterFilter { + $Body -and $Body['includeChildren'] -eq $true -and $Body['startOrganizationalUnitId'] -eq $example_uuid -and $Body['sortBy'] -eq 'Name' -and $Body['pageNumber'] -eq 2 -and $Body['sortOrder'] -eq 'Asc' -and $Body['pageSize'] -eq 200 } + } + + It 'Should fail with empty filter' { + { Get-TeamViewerOrganizationalUnit -ApiToken $testApiToken -Filter '' } | Should -Throw + + } + It 'Should accept OrgUnit object as input' { + $testGroupObj = @{ id = $example_uuid } | ConvertTo-TeamViewerOrganizationalUnit + + Get-TeamViewerOrganizationalUnit -ApiToken $testApiToken -Id $testGroupObj + + Should -Invoke Invoke-TeamViewerRestMethod -Times 1 -Scope It -ParameterFilter { + $ApiToken -eq $testApiToken -and ` + $Uri -eq '//unit.test/organizationalunits/' + $example_uuid -and ` + $Method -eq 'Get' } + } + + It 'Should accept pipeline objects' { + $testGroupObj = @{ id = $example_uuid } | ConvertTo-TeamViewerOrganizationalUnit + $testGroupObj | Get-TeamViewerOrganizationalUnit -ApiToken $testApiToken + + Should -Invoke Invoke-TeamViewerRestMethod -Times 1 -Scope It -ParameterFilter { + $ApiToken -eq $testApiToken -and ` + $Uri -eq '//unit.test/organizationalunits/' + $example_uuid -and ` + $Method -eq 'Get' } + } +} diff --git a/Tests/Public/New-TeamViewerOrganizationalUnit.Tests.ps1 b/Tests/Public/New-TeamViewerOrganizationalUnit.Tests.ps1 new file mode 100644 index 0000000..06d657c --- /dev/null +++ b/Tests/Public/New-TeamViewerOrganizationalUnit.Tests.ps1 @@ -0,0 +1,59 @@ +BeforeAll { + . "$PSScriptRoot\..\..\Cmdlets\Public\New-TeamViewerOrganizationalUnit.ps1" + + @(Get-ChildItem -Path "$PSScriptRoot\..\..\Cmdlets\Private\*.ps1") | ForEach-Object { . $_.FullName } + + $testApiToken = [securestring]@{} + $null = $testApiToken + $mockArgs = @{} + + Mock Get-TeamViewerApiUri { '//unit.test' } + Mock Invoke-TeamViewerRestMethod { $mockArgs.Body = $Body + @{ + name = 'Test22' + parentId = 'd696ef85-d40a-479e-8331-4813f59e6481' + id = 'cbe3195f-dd84-4e63-a922-fa337658d459' + description = '' + createdAt = '28/03/2025 16:07:16' + updatedAt = '28/03/2025 16:07:16' + } } +} + +Describe 'New-TeamViewerOrganizationalUnit' { + + It 'Should call the correct API endpoint' { + New-TeamViewerOrganizationalUnit -ApiToken $testApiToken -Name 'Test22' + + Should -Invoke Invoke-TeamViewerRestMethod -Times 1 -Scope It -ParameterFilter { + $ApiToken -eq $testApiToken -and $Uri -eq '//unit.test/organizationalunits' -and $Method -eq 'Post' } + } + + It 'Should include the given name, description and parent in the request' { + New-TeamViewerOrganizationalUnit -ApiToken $testApiToken -Name 'Unit Test' -Description 'Test' -Parent 'd696ef85-d40a-479e-8331-4813f59e6481' + + $mockArgs.Body | Should -Not -BeNullOrEmpty + $body = [System.Text.Encoding]::UTF8.GetString($mockArgs.Body) | ConvertFrom-Json + $body.name | Should -Be 'Unit Test' + $body.description | Should -Be 'Test' + $body.parentId | Should -Be 'd696ef85-d40a-479e-8331-4813f59e6481' + } + + It 'Should return the new org unit object' { + $result = New-TeamViewerOrganizationalUnit -ApiToken $testApiToken -Name 'Test22' -Parent 'd696ef85-d40a-479e-8331-4813f59e6481' + + $result | Should -Not -BeNullOrEmpty + $result.PSObject.TypeNames | Should -Contain 'TeamViewerPS.OrganizationalUnit' + $result.name | Should -Be 'Test22' + $result.parentId | Should -Be 'd696ef85-d40a-479e-8331-4813f59e6481' + } + + It 'Should allow to specify a description for the new org unit' { + $testDescription = 'Test description' + + New-TeamViewerOrganizationalUnit -ApiToken $testApiToken -Name 'Unit Test User' -Description $testDescription + + $mockArgs.Body | Should -Not -BeNullOrEmpty + $body = [System.Text.Encoding]::UTF8.GetString($mockArgs.Body) | ConvertFrom-Json + $body.description | Should -Be $testDescription + } +} diff --git a/Tests/Public/Remove-TeamViewerOrganizationalUnit.Tests.ps1 b/Tests/Public/Remove-TeamViewerOrganizationalUnit.Tests.ps1 new file mode 100644 index 0000000..48d7406 --- /dev/null +++ b/Tests/Public/Remove-TeamViewerOrganizationalUnit.Tests.ps1 @@ -0,0 +1,51 @@ +BeforeAll { + . "$PSScriptRoot\..\..\Cmdlets\Public\Remove-TeamViewerOrganizationalUnit.ps1" + + @(Get-ChildItem -Path "$PSScriptRoot\..\..\Cmdlets\Private\*.ps1") | ForEach-Object { . $_.FullName } + + $testApiToken = [securestring]@{} + $null = $testApiToken + + $example_uuid = '7042bac2-7ce0-47c6-8c1a-fb00505bd6ed' + $null = $example_uuid + + + Mock Get-TeamViewerApiUri { '//unit.test' } + Mock Invoke-TeamViewerRestMethod { } +} + +Describe 'Remove-TeamViewerOrganizationalUnit' { + + It 'Should call the correct API endpoint' { + Remove-TeamViewerOrganizationalUnit -ApiToken $testApiToken -Id $example_uuid + + Should -Invoke Invoke-TeamViewerRestMethod -Times 1 -Scope It -ParameterFilter { + $ApiToken -eq $testApiToken -and ` + $Uri -eq '//unit.test/organizationalunits/' + $example_uuid -and ` + $Method -eq 'Delete' } + } + + It 'Should accept org unit objects' { + $testOrgUnit = @{ id = $example_uuid } | ConvertTo-TeamViewerOrganizationalUnit + Remove-TeamViewerOrganizationalUnit -ApiToken $testApiToken -Id $testOrgUnit + + Should -Invoke Invoke-TeamViewerRestMethod -Times 1 -Scope It -ParameterFilter { + $ApiToken -eq $testApiToken -and ` + $Uri -eq '//unit.test/organizationalunits/' + $example_uuid -and ` + $Method -eq 'Delete' } + } + + It 'Should fail for invalid identifiers' { + { Remove-TeamViewerOrganizationalUnit -ApiToken $testApiToken -Id 'invalid1234' } | Should -Throw + } + + It 'Should accept pipeline input' { + $testOrgUnit = @{ id = $example_uuid } | ConvertTo-TeamViewerOrganizationalUnit + $testOrgUnit | Remove-TeamViewerOrganizationalUnit -ApiToken $testApiToken + + Should -Invoke Invoke-TeamViewerRestMethod -Times 1 -Scope It -ParameterFilter { + $ApiToken -eq $testApiToken -and ` + $Uri -eq '//unit.test/organizationalunits/' + $example_uuid -and ` + $Method -eq 'Delete' } + } +} diff --git a/Tests/Public/Set-TeamViewerOrganizationalUnit.Tests.ps1 b/Tests/Public/Set-TeamViewerOrganizationalUnit.Tests.ps1 new file mode 100644 index 0000000..fee3f23 --- /dev/null +++ b/Tests/Public/Set-TeamViewerOrganizationalUnit.Tests.ps1 @@ -0,0 +1,78 @@ +BeforeAll { + . "$PSScriptRoot\..\..\Cmdlets\Public\Set-TeamViewerOrganizationalUnit.ps1" + + @(Get-ChildItem -Path "$PSScriptRoot\..\..\Cmdlets\Private\*.ps1") | ForEach-Object { . $_.FullName } + + $testApiToken = [securestring]@{} + $null = $testApiToken + $testOrgId = 'f6bdc642-374e-4923-aac9-6845c73e322f' + $null = $testOrgId + $mockArgs = @{} + + Mock Get-TeamViewerApiUri { '//unit.test' } + Mock Invoke-TeamViewerRestMethod { $mockArgs.Body = $Body } +} + +Describe 'Set-TeamViewerOrganizationalUnit' { + + It 'Should call the correct API endpoint' { + Set-TeamViewerOrganizationalUnit -ApiToken $testApiToken -Id $testOrgId -Name 'Test Org' + + Should -Invoke Invoke-TeamViewerRestMethod -Times 1 -Scope It -ParameterFilter { + $ApiToken -eq $testApiToken -and ` + $Uri -eq '//unit.test/organizationalunits/' + $testOrgId -and ` + $Method -eq 'Put' } + } + + It 'Should include the given name in the request' { + Set-TeamViewerOrganizationalUnit -ApiToken $testApiToken -Id $testOrgId -Name 'Test Org' + + $mockArgs.Body | Should -Not -BeNullOrEmpty + $body = [System.Text.Encoding]::UTF8.GetString($mockArgs.Body) | ConvertFrom-Json + $body.name | Should -Be 'Test Org' + } + + It 'Should include the optional description in the request' { + Set-TeamViewerOrganizationalUnit -ApiToken $testApiToken -Id $testOrgId -Description 'test dec' + + $mockArgs.Body | Should -Not -BeNullOrEmpty + $body = [System.Text.Encoding]::UTF8.GetString($mockArgs.Body) | ConvertFrom-Json + $body.description | Should -Be 'test dec' + } + + It 'Should include the optional parent ID in the request' { + Set-TeamViewerOrganizationalUnit -ApiToken $testApiToken -Id $testOrgId -Parent $testOrgId + + $mockArgs.Body | Should -Not -BeNullOrEmpty + $body = [System.Text.Encoding]::UTF8.GetString($mockArgs.Body) | ConvertFrom-Json + $body.parentId | Should -Be $testOrgId + } + + It 'Should accept OrgUnit object as input' { + $testGroupObj = @{ id = $testOrgId } | ConvertTo-TeamViewerOrganizationalUnit + + Set-TeamViewerOrganizationalUnit -ApiToken $testApiToken -Id $testGroupObj + + Should -Invoke Invoke-TeamViewerRestMethod -Times 1 -Scope It -ParameterFilter { + $ApiToken -eq $testApiToken -and ` + $Uri -eq '//unit.test/organizationalunits/' + $testOrgId -and ` + $Method -eq 'Put' } + } + + It 'Should accept pipeline objects' { + $testGroupObj = @{ id = $testOrgId } | ConvertTo-TeamViewerOrganizationalUnit + $testGroupObj | Set-TeamViewerOrganizationalUnit -ApiToken $testApiToken -Name 'Unit Test Name' + + Should -Invoke Invoke-TeamViewerRestMethod -Times 1 -Scope It -ParameterFilter { + $ApiToken -eq $testApiToken -and ` + $Uri -eq '//unit.test/organizationalunits/' + $testOrgId -and ` + $Method -eq 'Put' } + } + + It 'Should throw if input is not a UUID' { + { Set-TeamViewerOrganizationalUnit ` + -ApiToken $testApiToken ` + -Id 'g1234' + } | Should -Throw + } +}