Closed jspern closed 1 year ago
@jspern, please share a complete repro of how you are creating windows10EndpointProtectionConfiguration
and calling New-MgDeviceManagementDeviceConfiguration
.
Please note that we use the same code generator as the Az module.
Here is a representation of expected formatting using a hashtable:
$NewConfigProfile = @{
DisplayName = 'DC001-Win10: Require BitLocker encryption on all portable devices-v1.0'
AdditionalProperties = @{
'@odata.type' = '#microsoft.graph.windows10EndpointProtectionConfiguration'
bitLockerEncryptDevice = $true
bitLockerSystemDrivePolicy = @{
startupAuthenticationRequired = $true
startupAuthenticationTpmUsage = 'allowed'
startupAuthenticationTpmPinUsage = 'allowed'
startupAuthenticationTpmKeyUsage = 'allowed'
startupAuthenticationTpmPinAndKeyUsage = 'allowed'
recoveryOptions = @{
recoveryPasswordUsage = 'allowed'
recoveryKeyUsage = 'allowed'
hideRecoveryOptions = $true
enableRecoveryInformationSaveToStore = $true
recoveryInformationToStore = 'passwordAndKey'
enableBitLockerAfterRecoveryInformationToStore = $true
}
}
bitLockerFixedDrivePolicy = @{
requireEncryptionForWriteAccess = $true
recoveryOptions = @{
recoveryPasswordUsage = 'allowed'
recoveryKeyUsage = 'allowed'
hideRecoveryOptions = $true
enableRecoveryInformationSaveToStore = $true
recoveryInformationToStore = 'passwordAndKey'
enableBitLockerAfterRecoveryInformationToStore = $true
}
}
}
}
Which is sent to the API endpoint like so:
New-MgDeviceManagementDeviceConfiguration @NewConfigProfile
The hashtables nested under AdditionalProperties
are discarded by the endpoint, unless they are of type System.Collections.Generic.Dictionary[System.String, System.Object]
, which results in the following code having to be used to create the object being sent to the endpoint:
$BitLockerSystemDrivePolicy = [System.Collections.Generic.Dictionary[System.String, System.Object]]::new()
$BitLockerSystemDrivePolicy.Add('startupAuthenticationRequired', $true)
$BitLockerSystemDrivePolicy.Add('startupAuthenticationBlockWithoutTpmChip', $false)
$BitLockerSystemDrivePolicy.Add('startupAuthenticationTpmUsage', 'allowed')
$BitLockerSystemDrivePolicy.Add('startupAuthenticationTpmPinUsage', 'allowed')
$BitLockerSystemDrivePolicy.Add('startupAuthenticationTpmKeyUsage', 'allowed')
$BitLockerSystemDrivePolicy.Add('startupAuthenticationTpmPinAndKeyUsage', 'allowed')
$BitLockerSystemDrivePolicy.Add('prebootRecoveryEnableMessageAndUrl', $false)
$BitLockerSystemDrivePolicyRecoveryOptions = [System.Collections.Generic.Dictionary[System.String, System.Object]]::new()
$BitLockerSystemDrivePolicyRecoveryOptions.Add('blockDataRecoveryAgent', $false)
$BitLockerSystemDrivePolicyRecoveryOptions.Add('recoveryPasswordUsage', 'allowed')
$BitLockerSystemDrivePolicyRecoveryOptions.Add('recoveryKeyUsage', 'allowed')
$BitLockerSystemDrivePolicyRecoveryOptions.Add('hideRecoveryOptions', $true)
$BitLockerSystemDrivePolicyRecoveryOptions.Add('enableRecoveryInformationSaveToStore', $true)
$BitLockerSystemDrivePolicyRecoveryOptions.Add('recoveryInformationToStore', 'passwordAndKey')
$BitLockerSystemDrivePolicyRecoveryOptions.Add('enableBitLockerAfterRecoveryInformationToStore', $true)
$BitLockerSystemDrivePolicy.Add('recoveryOptions', $BitLockerSystemDrivePolicyRecoveryOptions)
$BitLockerFixedDrivePolicy = [System.Collections.Generic.Dictionary[System.String, System.Object]]::new()
$BitLockerFixedDrivePolicy.Add('requireEncryptionForWriteAccess', $true)
$BitLockerFixedDrivePolicyRecoveryOptions = [System.Collections.Generic.Dictionary[System.String, System.Object]]::new()
$BitLockerFixedDrivePolicyRecoveryOptions.Add('blockDataRecoveryAgent', $false)
$BitLockerFixedDrivePolicyRecoveryOptions.Add('recoveryPasswordUsage', 'allowed')
$BitLockerFixedDrivePolicyRecoveryOptions.Add('recoveryKeyUsage', 'allowed')
$BitLockerFixedDrivePolicyRecoveryOptions.Add('hideRecoveryOptions', $true)
$BitLockerFixedDrivePolicyRecoveryOptions.Add('enableRecoveryInformationSaveToStore', $true)
$BitLockerFixedDrivePolicyRecoveryOptions.Add('recoveryInformationToStore', 'passwordAndKey')
$BitLockerFixedDrivePolicyRecoveryOptions.Add('enableBitLockerAfterRecoveryInformationToStore', $true)
$BitLockerFixedDrivePolicy.Add('recoveryOptions', $BitLockerFixedDrivePolicyRecoveryOptions)
$ConfigProfile = @{
DisplayName = 'DC001-Win10: Require BitLocker encryption on all portable devices-v1.0'
AdditionalProperties = @{
'@odata.type' = '#microsoft.graph.windows10EndpointProtectionConfiguration'
bitLockerEncryptDevice = $true
bitLockerSystemDrivePolicy = $BitLockerSystemDrivePolicy
bitLockerFixedDrivePolicy = $BitLockerFixedDrivePolicy
}
}
Thanks for the repro steps!
This is due to the same root cause as https://github.com/Azure/azure-powershell/issues/12267 since we share the same code generator. A fix will need to come for the shared code generator, Azure's AutoREST.PowerShell.
I'll open an issue against AutoREST.PowerShell repo to track this serialization bug.
The issue is no longer reproducible in v2.x (tested the repro steps above with v2.1.0). Here is the serialized output of $NewConfigProfile
that's sent to the service:
➜ New-MgDeviceManagementDeviceConfiguration @NewConfigProfile -Debug
Confirm
Are you sure you want to perform this action?
Performing the operation "New-MgDeviceManagementDeviceConfiguration_CreateExpanded" on target "Call remote 'POST
/deviceManagement/deviceConfigurations' operation".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"): A
DEBUG: ============================ HTTP REQUEST ============================
HTTP Method:
POST
Absolute Uri:
https://graph.microsoft.com/v1.0/deviceManagement/deviceConfigurations
Headers:
FeatureFlag : 00000043
Cache-Control : no-store, no-cache
User-Agent : Mozilla/5.0,(Windows NT 10.0; Microsoft Windows 10.0.22621; en-US),PowerShell/7.3.6
Accept-Encoding : gzip
SdkVersion : graph-powershell/2.1.0
client-request-id : 37dd01be-ac13-4ca3-8e5f-40f1ea18d4d1
Body:
{
"@odata.type": "#microsoft.graph.windows10EndpointProtectionConfiguration",
"bitLockerSystemDrivePolicy": {
"startupAuthenticationTpmPinUsage": "allowed",
"startupAuthenticationTpmPinAndKeyUsage": "allowed",
"startupAuthenticationTpmKeyUsage": "allowed",
"recoveryOptions": {
"recoveryInformationToStore": "passwordAndKey",
"enableRecoveryInformationSaveToStore": true,
"recoveryPasswordUsage": "allowed",
"enableBitLockerAfterRecoveryInformationToStore": true,
"recoveryKeyUsage": "allowed",
"hideRecoveryOptions": true
},
"startupAuthenticationRequired": true,
"startupAuthenticationTpmUsage": "allowed"
},
"bitLockerFixedDrivePolicy": {
"requireEncryptionForWriteAccess": true,
"recoveryOptions": {
"recoveryInformationToStore": "passwordAndKey",
"enableRecoveryInformationSaveToStore": true,
"recoveryPasswordUsage": "allowed",
"enableBitLockerAfterRecoveryInformationToStore": true,
"recoveryKeyUsage": "allowed",
"hideRecoveryOptions": true
}
},
"bitLockerEncryptDevice": true,
"displayName": "DC001-Win10: Require BitLocker encryption on all portable devices-v1.0"
}
This issue has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for 4 days. It will be closed if no further activity occurs within 3 days of this comment.
I'm sorry to say that I am still able to reproduce this issue, even with the current version of 2.2.0. The bitLockerSystemDrivePolicy
and bitLockerFixedDrivePolicy
objects are being completely discarded upon submission, by which I mean the only setting that is applied to the resulting profile is the bitLockerEncryptDevice
setting.
I did some more testing and it appears that both of the methods I mentioned in the original post are now not working. This is using the -DisplayName
and -AdditionalProperties
parameters. If I instead use the -BodyParameter
parameter with the object constructed like below, it does work, but only with the Beta module:
$ConfigProfile = @{
DisplayName = 'DC001-Win10: Require BitLocker encryption on all portable devices-v1.0'
'@odata.type' = '#microsoft.graph.windows10EndpointProtectionConfiguration'
bitLockerEncryptDevice = $true
bitLockerSystemDrivePolicy = @{
'@odata.type' = '#microsoft.graph.bitLockerSystemDrivePolicy'
startupAuthenticationRequired = $true
startupAuthenticationBlockWithoutTpmChip = $false
startupAuthenticationTpmUsage = 'allowed'
startupAuthenticationTpmPinUsage = 'allowed'
startupAuthenticationTpmKeyUsage = 'allowed'
prebootRecoveryEnableMessageAndUrl = $false
recoveryOptions = @{
'@odata.type' = '#microsoft.graph.bitLockerRecoveryOptions'
blockDataRecoveryAgent = $false
recoveryPasswordUsage = 'allowed'
recoveryKeyUsage = 'allowed'
hideRecoveryOptions = $true
enableRecoveryInformationSaveToStore = $true
recoveryInformationToStore = 'passwordAndKey'
enableBitLockerAfterRecoveryInformationToStore = $true
}
}
}
New-MgBetaDeviceManagementDeviceConfiguration -BodyParameter $ConfigProfile
Similar to this open issue for the Azure module, when creating device configuration profiles of certain types (perhaps all of them, although I only verified for one), there are nested properties that will not be set on the resulting configuration profile if they are in hashtable format; it will only work if they are
System.Collections.Generic.Dictionary[System.String, System.Object]
. I have confirmed this while trying to create#microsoft.graph.windows10EndpointProtectionConfiguration
type configuration profiles.In my example,
AddtionalProperties.bitLockerSystemDrivePolicy
andAdditionalProperties.bitLockerFixedDrivePolicy
are two such properties that I am forced to use dictionaries for.