functions/device/Set-PSEntraIDDeviceExtensionAttribute.ps1
|
function Set-PSEntraIDDeviceExtensionAttribute { <# .SYNOPSIS Set or clear one extension attribute of an Entra ID device. .DESCRIPTION PATCHes the extensionAttributes property of a directory device object (Graph: Update device). extensionAttributes is the one device property an app-only caller may update - Device.ReadWrite.All suffices - and the property dynamic device group rules can target (device.extensionAttribute1..15). The device can be addressed three ways: by piped device object, by the directory object id, or by the device GUID (DeviceId - the same value Defender for Endpoint reports as aadDeviceId), which Graph accepts directly as devices(deviceId='...') without an object-id lookup. .PARAMETER InputObject Device object(s) as returned by Get-PSEntraIDDevice. .PARAMETER Identity The directory object id(s) of the device (device.id). .PARAMETER DeviceId The device GUID(s) (device.deviceId / MDE aadDeviceId). .PARAMETER AttributeName Which attribute to write: extensionAttribute1 through extensionAttribute15. .PARAMETER Value The value to set. An empty or null value CLEARS the attribute (Graph clears with null; an empty string would be stored literally otherwise). .PARAMETER WhatIf Enables the function to simulate what it will do instead of actually executing. .PARAMETER Confirm Prompts for confirmation before the command makes a change. -Confirm:$false suppresses that prompt. Bound explicitly it wins over -Force, whatever its value - so -Confirm:$true prompts even alongside -Force, and the two are alternatives rather than a pair. .PARAMETER EnableException This parameter disables user-friendly warnings and enables the throwing of exceptions. This is less user friendly, but allows catching exceptions in calling scripts. .PARAMETER Force The Force switch instructs the command to which object the specific query is applied without asking for confirmation. .PARAMETER PassThru Instead of executing the request, return a PSMicrosoftEntraID.Batch.Request for New-PSEntraIDBatchRequest / Invoke-PSEntraIDBatchRequest. .EXAMPLE PS C:\> Set-PSEntraIDDeviceExtensionAttribute -DeviceId $machine.AadDeviceId -AttributeName extensionAttribute10 -Value 'vip' Writes the value into extensionAttribute10 of the device matched by its GUID. .EXAMPLE PS C:\> Get-PSEntraIDDevice -Identity 'IT3C-JB-SEP2MDE' | Set-PSEntraIDDeviceExtensionAttribute -AttributeName extensionAttribute10 -Value '' Clears extensionAttribute10 on the device. #> [OutputType([PSMicrosoftEntraID.Batch.Request])] [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium', DefaultParameterSetName = 'InputObject')] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'InputObject')] [PSMicrosoftEntraID.Devices.Device[]] $InputObject, [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'Identity')] [Alias('Id')] [ValidateNotNullOrEmpty()] [string[]] $Identity, [Parameter(Mandatory = $true, ParameterSetName = 'DeviceId')] [Alias('AadDeviceId')] [guid[]] $DeviceId, [Parameter(Mandatory = $true)] [ValidatePattern('^extensionAttribute([1-9]|1[0-5])$')] [string] $AttributeName, [Parameter(Mandatory = $true)] [AllowNull()] [AllowEmptyString()] [string] $Value, [Parameter()] [switch] $EnableException, [Parameter()] [switch] $Force, [Parameter()] [switch] $PassThru ) begin { [string] $service = Get-PSFConfigValue -FullName ('{0}.Settings.DefaultService' -f $script:ModuleName) Assert-EntraConnection -Service $service -Cmdlet $PSCmdlet [int] $commandRetryCount = Get-PSFConfigValue -FullName ('{0}.Settings.Command.RetryCount' -f $script:ModuleName) [System.TimeSpan] $commandRetryWait = New-TimeSpan -Seconds (Get-PSFConfigValue -FullName ('{0}.Settings.Command.RetryWaitInSeconds' -f $script:ModuleName)) [hashtable] $header = @{ 'Content-Type' = 'application/json' } [hashtable] $cmdLetConfirm = Resolve-PSEntraIDConfirmPreference -BoundParameters $PSBoundParameters -Force:$Force -Confirm:$Confirm # Graph clears an extension attribute with null - an empty string would be # stored literally and a dynamic group rule would then match ''. $attributeValue = if ([string]::IsNullOrEmpty($Value)) { $null } else { $Value } [hashtable] $body = @{ extensionAttributes = @{ $AttributeName = $attributeValue } } } process { [string[]] $pathList = switch ($PSCmdlet.ParameterSetName) { 'InputObject' { foreach ($item in $InputObject) { 'devices/{0}' -f $item.Id } } 'Identity' { foreach ($item in $Identity) { 'devices/{0}' -f $item } } 'DeviceId' { foreach ($item in $DeviceId) { "devices(deviceId='{0}')" -f $item.Guid } } } foreach ($path in $pathList) { if ($PassThru.IsPresent) { [PSMicrosoftEntraID.Batch.Request]@{ Method = 'PATCH'; Url = ('/{0}' -f $path); Body = $body; Headers = $header } } else { Invoke-PSFProtectedCommand -ActionString 'Device.ExtensionAttribute.Set' -ActionStringValues $AttributeName, $path -Target (Get-PSFLocalizedString -Module $script:ModuleName -Name Identity.Platform) -ScriptBlock { [void] (Invoke-EntraRequest -Service $service -Path $path -Header $header -Body $body -Method Patch -ErrorAction Stop) } -EnableException:$EnableException @cmdLetConfirm -PSCmdlet $PSCmdlet -Continue -RetryCount $commandRetryCount -RetryWait $commandRetryWait if (Test-PSFFunctionInterrupt) { return } } } } end {} } |