public/Update-VSAUser.ps1
|
function Update-VSAUser { <# .Synopsis Updates a single user account record. .DESCRIPTION Updates a single user account record. Takes either persistent or non-persistent connection information. .PARAMETER VSAConnection Specifies existing non-persistent VSAConnection. .PARAMETER URISuffix Specifies URI suffix if it differs from the default. .PARAMETER UserId Specifies a user account Id. .PARAMETER AdminName Specifies a user account name. .PARAMETER DefaultStaffDepartmentId Specifies the Department Id to which a user is added. .PARAMETER DefaultStaffOrgId Specifies the Organization Id to which a user is added. .PARAMETER DefaultStaffOrgName Specifies the Organization Name to which a user is added. .PARAMETER FirstName Specifies user's first name. .PARAMETER LastName Specifies user's last name. .PARAMETER Email Specifies user's e-mail. .PARAMETER AdminRoleIds Specifies Ids of user's admin roles. .PARAMETER AdminRoleNames Specifies user's admin roles. .PARAMETER AdminScopeIds Specifies Ids of user's admin scopes. .PARAMETER AdminScopeNames Specifies user's admin scopes. .PARAMETER AdminType Specifies Id of user's admin type. .EXAMPLE $securePassword = ConvertTo-SecureString 'P@$$w0rd!' -AsPlainText -Force Update-VSAUser -UserId 10001 -AdminName 'Login' -AdminPassword $securePassword -AdminRoleIds 1, 2 -AdminScopeIds 3, 4 -DefaultStaffOrgId 5 -DefaultStaffDepartmentId 6 -FirstName 'John' -LastName 'Doe' -Email 'JohnDoe@example.mail' .INPUTS Accepts piped non-persistent VSAConnection .OUTPUTS True if update was successful. #> [CmdletBinding(DefaultParameterSetName = 'ById')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingUsernameAndPasswordParams','')] #[CmdletBinding()] param ( [parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ByName')] [parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ById')] [ValidateNotNull()] [VSAConnection] $VSAConnection, [parameter(Mandatory=$false, ParameterSetName = 'ByName')] [parameter(Mandatory=$false, ParameterSetName = 'ById')] [ValidateNotNullOrEmpty()] [string] $URISuffix = 'api/v1.0/system/users/{0}', [parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true, ParameterSetName = 'ById')] [decimal] $UserId, [parameter(Mandatory=$false, ValueFromPipelineByPropertyName=$true, ParameterSetName = 'ByName')] [parameter(Mandatory=$false, ValueFromPipelineByPropertyName=$true, ParameterSetName = 'ById')] [ValidateNotNull()] [securestring] $AdminPassword, [parameter(DontShow, Mandatory=$false, ValueFromPipelineByPropertyName=$true, ParameterSetName = 'ByName')] [parameter(DontShow, Mandatory=$false, ValueFromPipelineByPropertyName=$true, ParameterSetName = 'ById')] [decimal] $AdminType, [parameter(Mandatory=$false, ValueFromPipelineByPropertyName=$true, ParameterSetName = 'ById')] [ValidateScript({ foreach ($item in $_) { if ( -not [decimal]::TryParse($item, [ref]$null) ) { throw "All elements must be numeric. '$item' is not a valid number." } } return $true })] [decimal[]] $AdminRoleIds, [parameter(Mandatory=$false, ValueFromPipelineByPropertyName=$true, ParameterSetName = 'ById')] [ValidateScript({ foreach ($item in $_) { if ( -not [decimal]::TryParse($item, [ref]$null) ) { throw "All elements must be numeric. '$item' is not a valid number." } } return $true })] [decimal[]] $AdminScopeIds, [parameter(Mandatory=$false, ValueFromPipelineByPropertyName=$true, ParameterSetName = 'ById')] [decimal] $DefaultStaffOrgId, [parameter(Mandatory=$false, ValueFromPipelineByPropertyName=$true, ParameterSetName = 'ById')] [parameter(Mandatory=$false, ValueFromPipelineByPropertyName=$true, ParameterSetName = 'ByName')] [decimal] $DefaultStaffDepartmentId, [parameter(Mandatory=$false, ValueFromPipelineByPropertyName=$true, ParameterSetName = 'ById')] [parameter(Mandatory=$false, ValueFromPipelineByPropertyName=$true, ParameterSetName = 'ByName')] [ValidateNotNullOrEmpty()] [string] $FirstName, [parameter(Mandatory=$false, ValueFromPipelineByPropertyName=$true, ParameterSetName = 'ById')] [parameter(Mandatory=$false, ValueFromPipelineByPropertyName=$true, ParameterSetName = 'ByName')] [ValidateNotNullOrEmpty()] [string] $LastName, [parameter(Mandatory=$false, ValueFromPipelineByPropertyName=$true, ParameterSetName = 'ById')] [parameter(Mandatory=$false, ValueFromPipelineByPropertyName=$true, ParameterSetName = 'ByName')] [ValidateNotNullOrEmpty()] [string] $Email, [parameter(DontShow, Mandatory=$false, ValueFromPipelineByPropertyName=$true, ParameterSetName = 'ById')] [parameter(DontShow, Mandatory=$false, ValueFromPipelineByPropertyName=$true, ParameterSetName = 'ByName')] [ValidateNotNullOrEmpty()] [hashtable] $Attributes, # ByName selectors. These were a DynamicParam block that eagerly called Get-VSAUser/ # Get-VSARoles/Get-VSAScope/Get-VSAOrganization on every tab-completion and Get-Command # introspection (F-44 / A-2). They are now static parameters with lazy, best-effort # [ArgumentCompleter]s; Name->Id resolution happens in Begin, only when the cmdlet runs. [parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true, ParameterSetName='ByName')] [ArgumentCompleter({ param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) try { $CompleterParams = @{} if ($fakeBoundParameters['VSAConnection']) { $CompleterParams['VSAConnection'] = $fakeBoundParameters['VSAConnection'] } Get-VSAUser @CompleterParams -ErrorAction Stop | Select-Object -ExpandProperty AdminName | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) } } catch { } })] [ValidateNotNullOrEmpty()] [string[]] $AdminName, [parameter(Mandatory=$false, ValueFromPipelineByPropertyName=$true, ParameterSetName='ByName')] [ArgumentCompleter({ param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) try { $CompleterParams = @{} if ($fakeBoundParameters['VSAConnection']) { $CompleterParams['VSAConnection'] = $fakeBoundParameters['VSAConnection'] } Get-VSARoles @CompleterParams -ErrorAction Stop | Select-Object -ExpandProperty RoleName | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) } } catch { } })] [string[]] $AdminRoleNames, [parameter(Mandatory=$false, ValueFromPipelineByPropertyName=$true, ParameterSetName='ByName')] [ArgumentCompleter({ param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) try { $CompleterParams = @{} if ($fakeBoundParameters['VSAConnection']) { $CompleterParams['VSAConnection'] = $fakeBoundParameters['VSAConnection'] } Get-VSAScope @CompleterParams -ErrorAction Stop | Select-Object -ExpandProperty ScopeName | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) } } catch { } })] [string[]] $AdminScopeNames, [parameter(Mandatory=$false, ValueFromPipelineByPropertyName=$true, ParameterSetName='ByName')] [ArgumentCompleter({ param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) try { $CompleterParams = @{} if ($fakeBoundParameters['VSAConnection']) { $CompleterParams['VSAConnection'] = $fakeBoundParameters['VSAConnection'] } Get-VSAOrganization @CompleterParams -ErrorAction Stop | Select-Object -ExpandProperty OrgName | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) } } catch { } })] [string[]] $DefaultStaffOrgName ) Begin { # Resolve the ByName selectors to their Ids with single targeted lookups, only when the # cmdlet actually runs -- never during parameter/command discovery (F-44 / A-2). Logic and # variable targets are unchanged from the former DynamicParam+Begin; only the data source # moved from eagerly-cached module-scope arrays to on-demand calls here. if ($PSCmdlet.ParameterSetName -eq 'ByName') { [hashtable] $AuxParameters = @{} if($VSAConnection) {$AuxParameters.Add('VSAConnection', $VSAConnection)} if ( -not $UserId ) { $UserId = Get-VSAUser @AuxParameters | Where-Object {$_.AdminName -eq $AdminName } | Select-Object -ExpandProperty UserId } if ( (0 -eq $AdminRoleIds.Count) -and (0 -lt $AdminRoleNames.Count) ) { $AdminRoleIds = Get-VSARoles @AuxParameters | Where-Object {$_.RoleName -in $AdminRoleNames } | Select-Object -ExpandProperty RoleId } if ( (0 -eq $AdminScopeIds.Count) -and (0 -lt $AdminScopeNames.Count) ) { $AdminScopeIds = Get-VSAScope @AuxParameters | Where-Object {$_.ScopeName -in $AdminScopeNames } | Select-Object -ExpandProperty ScopeId } if ( (-not $DefaultStaffOrgId) -and (-not [string]::IsNullOrEmpty($DefaultStaffOrgName)) ) { $DefaultStaffOrgId = Get-VSAOrganization @AuxParameters | Where-Object {$_.OrgName -eq $DefaultStaffOrgName } | Select-Object -ExpandProperty OrgId } # The Process body-prune keeps only keys present in $PSBoundParameters. In the ByName set # these Ids are resolved here (not bound from input), so without registering them they # would be silently dropped from the update body (F-25). Register the ones we resolved. if ( $UserId ) { $PSBoundParameters['UserId'] = $UserId } if ( $AdminRoleIds.Count ) { $PSBoundParameters['AdminRoleIds'] = $AdminRoleIds } if ( $AdminScopeIds.Count ) { $PSBoundParameters['AdminScopeIds'] = $AdminScopeIds } if ( $DefaultStaffOrgId ) { $PSBoundParameters['DefaultStaffOrgId'] = $DefaultStaffOrgId } } }# Begin Process { # Convert SecureString password to plaintext for API transmission if provided $PasswordForBody = $AdminPassword if ($AdminPassword -and $AdminPassword -is [securestring]) { $passwordPtr = [System.Runtime.InteropServices.Marshal]::SecureStringToGlobalAllocUnicode($AdminPassword) $PasswordForBody = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($passwordPtr) [System.Runtime.InteropServices.Marshal]::ZeroFreeGlobalAllocUnicode($passwordPtr) } [hashtable]$BodyHT = @{ UserId = $UserId AdminName = $AdminName AdminPassword = $PasswordForBody AdminScopeIds = $AdminScopeIds AdminRoleIds = $AdminRoleIds FirstName = $FirstName LastName = $LastName DefaultStaffOrgId = $DefaultStaffOrgId DefaultStaffDepartmentId = $DefaultStaffDepartmentId Email = $Email Attributes = $Attributes } # The plaintext password now lives only inside $BodyHT (for JSON serialization below); clear # the standalone variable immediately so it doesn't linger in memory (T-5.5 / F-55). $PasswordForBody = $null # Prune by whether the caller actually bound the parameter, not by truthiness (F-52): a # truthiness check would silently drop legitimate values like 0 or '' that a caller explicitly # asked to send. foreach ( $key in @($BodyHT.Keys) ) { if ( -not $PSBoundParameters.ContainsKey($key)) { $BodyHT.Remove($key) } } [hashtable]$Params = @{ URISuffix = $($URISuffix -f $UserId) Method = 'PUT' Body = $(ConvertTo-Json $BodyHT -Depth 5 -Compress) } if($VSAConnection) {$Params.Add('VSAConnection', $VSAConnection)} return Invoke-VSARestMethod @Params } } Export-ModuleMember -Function Update-VSAUser |