Initial 3.10.0 upload

This commit is contained in:
Mikael Karlsson
2025-02-22 21:52:13 +11:00
parent 17e9b786be
commit 8601a5b38e
68 changed files with 10592 additions and 26993 deletions

View File

@@ -188,6 +188,12 @@ function Show-CompareBulkForm
$global:chkSkipCompareAssignments.IsChecked = (Get-Setting "Compare" "SkipCompareAssignments") -eq "true"
$global:chkSkipMissingSourcePolicies.IsChecked = (Get-Setting "Compare" "SkipMissingSourcePolicies") -eq "true"
$global:chkSkipMissingDestinationPolicies.IsChecked = (Get-Setting "Compare" "SkipMissingDestinationPolicies") -eq "true"
$global:chkBulkCompareSaveJson.IsChecked = (Get-Setting "Compare" "SaveJson") -eq "true"
$global:chkBulkCompareRemoveOData.IsChecked = (Get-Setting "Compare" "RemoveOData") -eq "true"
$objectSeparator = "[ { Name: `"New line`",Value: `"$([System.Environment]::NewLine)`" }, {Name: `";`",Value: `";`" }, {Name: `"|`",Value: `"|`" }]" | ConvertFrom-Json
$global:cbCompareMultiValueDelimiter.ItemsSource = $objectSeparator
$global:cbCompareMultiValueDelimiter.SelectedValue = (Get-Setting "Compare" "ObjectSeparator" ([System.Environment]::NewLine))
$script:compareObjects = @()
foreach($objType in $global:lstMenuItems.ItemsSource)
@@ -239,6 +245,9 @@ function Show-CompareBulkForm
Save-Setting "Compare" "SkipCompareAssignments" $global:chkSkipCompareAssignments.IsChecked
Save-Setting "Compare" "SkipMissingSourcePolicies" $global:chkSkipMissingSourcePolicies.IsChecked
Save-Setting "Compare" "SkipMissingDestinationPolicies" $global:chkSkipMissingDestinationPolicies.IsChecked
Save-Setting "Compare" "SaveJson" $global:chkBulkCompareSaveJson.IsChecked
Save-Setting "Compare" "RemoveOData" $global:chkBulkCompareRemoveOData.IsChecked
Save-Setting "Compare" "ObjectSeparator" $global:cbCompareMultiValueDelimiter.SelectedValue
if($global:cbCompareProvider.SelectedItem.BulkCompare)
{
@@ -534,6 +543,10 @@ function Invoke-BulkCompareNamedObjects
{
$fileName = Remove-InvalidFileNameChars (Expand-FileName "Compare-$($graphObj.ObjectType.Id)-$sourcePattern-$comparePattern-%DateTime%.csv")
Save-BulkCompareResults $compResultValues (Join-Path $outputFolder $fileName) $compareProps
if($global:chkBulkCompareSaveJson.IsChecked) {
$fileName = Remove-InvalidFileNameChars (Expand-FileName "Compare-$($graphObj.ObjectType.Id)-$sourcePattern-$comparePattern-%DateTime%.json")
Save-BulkCompareJsonResults $compResultValues (Join-Path $rootFolder $fileName)
}
}
}
#$fileName = Expand-FileName $fileName
@@ -546,6 +559,10 @@ function Invoke-BulkCompareNamedObjects
{
$fileName = Remove-InvalidFileNameChars (Expand-FileName "Compare-$sourcePattern-$comparePattern-%DateTime%.csv")
Save-BulkCompareResults $compResultValues (Join-Path $outputFolder $fileName) $compareProps
if($global:chkBulkCompareSaveJson.IsChecked) {
$fileName = Remove-InvalidFileNameChars (Expand-FileName "Compare-$($graphObj.ObjectType.Id)-$sourcePattern-$comparePattern-%DateTime%.json")
Save-BulkCompareJsonResults $compResultValues (Join-Path $rootFolder $fileName)
}
}
}
@@ -689,7 +706,7 @@ function Start-BulkCompareExportObjects
$objName = Get-GraphObjectName (?? $compObj.Object1 $compObj.Object2) $item.ObjectType
foreach($compValue in $compObj.Result)
{
$compResultValues += [PSCustomObject]@{
$compValue += [PSCustomObject]@{
ObjectName = $objName
Id = $compObj.Id
Type = $compObj.ObjectType.Title
@@ -701,12 +718,34 @@ function Start-BulkCompareExportObjects
SubCategory = $compValue.SubCategory
Match = $compValue.Match
}
if($global:chkBulkCompareRemoveOData.IsChecked -and ($compValue.Value1 -like "@odata*" -or $compValue.Value2 -like "@odata*")) {
foreach($prop in $('Value1','Value2'))
{
$tmpValue1 = ""
$tmpValue2 = ""
$vauleString = $compValue.$prop
if($vauleString -is [String]) {
$vauleString = $vauleString -replace $compValue.Id, ""
$tmpObj = $compValue.$prop | ConvertFrom-Json
if($compValue.$prop -and $compValue.$prop -like "@odata*") {
Remove-GraphODataProperties $tmpObj.$prop | ConvertTo-Json -Depth 50 | Set-Variable -Name "tmp$prop"
}
}
}
$compValue.Match = $tmpValue1 -eq $tmpValue2
}
$compResultValues += $compValue
}
}
if($outputType -eq "objectType")
{
Save-BulkCompareResults $compResultValues (Join-Path $folder "Compare_$(((Get-Date).ToString("yyyyMMdd-HHmm"))).csv") $compareProps
Save-BulkCompareResults $compResultValues (Join-Path $folder "Compare_$(((Get-Date).ToString("yyyyMMdd-HHmm"))).csv") $compareProps
if($global:chkBulkCompareSaveJson.IsChecked) {
Save-BulkCompareJsonResults $compResultValues (Join-Path $folder "Compare_$(((Get-Date).ToString("yyyyMMdd-HHmm"))).json")
}
}
}
else
@@ -717,7 +756,10 @@ function Start-BulkCompareExportObjects
if($outputType -eq "all" -and $compResultValues.Count -gt 0)
{
Save-BulkCompareResults $compResultValues (Join-Path $rootFolder "Compare_$(((Get-Date).ToString("yyyyMMDD-HHmm"))).csv") $compareProps
Save-BulkCompareResults $compResultValues (Join-Path $rootFolder "Compare_$(((Get-Date).ToString("yyyyMMdd-HHmm"))).csv") $compareProps
if($global:chkBulkCompareSaveJson.IsChecked) {
Save-BulkCompareJsonResults $compResultValues (Join-Path $rootFolder "Compare_$(((Get-Date).ToString("yyyyMMdd-HHmm"))).json")
}
}
Write-Log "****************************************************************"
@@ -726,7 +768,7 @@ function Start-BulkCompareExportObjects
Write-Status ""
if($compareObjectsResult.Count -eq 0)
{
[System.Windows.MessageBox]::Show("No objects were comparced. Verify folder and exported files", "Error", "OK", "Error")
[System.Windows.MessageBox]::Show("No objects were compared. Verify folder and exported files", "Error", "OK", "Error")
}
}
@@ -796,6 +838,7 @@ function Start-BulkCompareExportIntuneToNamedExportedObjects
if($txtNameFilter -and $objName -notmatch [RegEx]::Escape($txtNameFilter))
{
Write-LogDebug "Excluded based on filter. Intune object name: '$($objName)'"
continue
}
@@ -803,7 +846,7 @@ function Start-BulkCompareExportIntuneToNamedExportedObjects
if(-not $fileObj)
{
# Add objects that are exported but deleted
# Add objects that are in Intune but no exported file found
if($global:chkSkipMissingDestinationPolicies.IsChecked -ne $true) {
Write-Log "Object '$($objName)' with id $($fileObj.Object.Id) not found in exported folder. New Object?" 2
$compareProperties = @([PSCustomObject]@{
@@ -815,7 +858,7 @@ function Start-BulkCompareExportIntuneToNamedExportedObjects
}
elseif(($fileObj | measure).Count -gt 1)
{
# Add objects that are exported but deleted
# Add objects where multiple files match based on name
Write-Log "Multiple exported objects found with name '$($objName)" 2
$compareProperties = @([PSCustomObject]@{
Object1Value = $objName
@@ -833,7 +876,7 @@ function Start-BulkCompareExportIntuneToNamedExportedObjects
$compareObjectsResult += [PSCustomObject]@{
Object1 = $graphObject.Object
Object2 = $fileObj.Object
Object2 = $fileObj.Object
ObjectType = $item.ObjectType
Id = $graphObject.Object.Id
Result = $compareProperties
@@ -843,12 +886,16 @@ function Start-BulkCompareExportIntuneToNamedExportedObjects
if($global:chkSkipMissingSourcePolicies.IsChecked -ne $true) {
foreach ($fileObj in @($fileObjects))
{
# Add objects that are exported but not in Intune
if(($compareObjectsResult | Where { $_.FileInfo.FullName -eq $fileObj.FileInfo.FullName})) { continue }
# Skip objects if they are already processed
if(($compareObjectsResult | Where { $_.Object2 -eq $fileObj.Object})) {
Write-LogDebug "Skip already processed file '$($fileObj.FileInfo.FullName)'"
continue
}
$objName = Get-GraphObjectName $fileObj.Object $item.ObjectType
if($txtNameFilter -and $objName -notmatch [RegEx]::Escape($txtNameFilter))
{
Write-LogDebug "Excluded based on filter. File: '$($fileObj.FileInfo.FullName)'"
continue
}
@@ -894,6 +941,9 @@ function Start-BulkCompareExportIntuneToNamedExportedObjects
if($outputType -eq "objectType")
{
Save-BulkCompareResults $compResultValues (Join-Path $folder "Compare_$(((Get-Date).ToString("yyyyMMdd-HHmm"))).csv") $compareProps
if($global:chkBulkCompareSaveJson.IsChecked) {
Save-BulkCompareJsonResults $compResultValues (Join-Path $rootFolder "Compare_$(((Get-Date).ToString("yyyyMMdd-HHmm"))).json")
}
}
}
else
@@ -904,7 +954,10 @@ function Start-BulkCompareExportIntuneToNamedExportedObjects
if($outputType -eq "all" -and $compResultValues.Count -gt 0)
{
Save-BulkCompareResults $compResultValues (Join-Path $rootFolder "Compare_$(((Get-Date).ToString("yyyyMMDD-HHmm"))).csv") $compareProps
Save-BulkCompareResults $compResultValues (Join-Path $rootFolder "Compare_$(((Get-Date).ToString("yyyyMMdd-HHmm"))).csv") $compareProps
if($global:chkBulkCompareSaveJson.IsChecked) {
Save-BulkCompareJsonResults $compResultValues (Join-Path $rootFolder "Compare_$(((Get-Date).ToString("yyyyMMdd-HHmm"))).json")
}
}
Write-Log "****************************************************************"
@@ -1080,6 +1133,9 @@ function Start-BulkCompareExportFolders
if($outputType -eq "objectType")
{
Save-BulkCompareResults $compResultValues (Join-Path $folderSource "Compare_$(((Get-Date).ToString("yyyyMMdd-HHmm"))).csv") $compareProps
if($global:chkBulkCompareSaveJson.IsChecked) {
Save-BulkCompareJsonResults $compResultValues (Join-Path $rootFolder "Compare_$(((Get-Date).ToString("yyyyMMdd-HHmm"))).json")
}
}
}
else
@@ -1090,7 +1146,10 @@ function Start-BulkCompareExportFolders
if($outputType -eq "all" -and $compResultValues.Count -gt 0)
{
Save-BulkCompareResults $compResultValues (Join-Path $rootFolderSource "Compare_$(((Get-Date).ToString("yyyyMMDD-HHmm"))).csv") $compareProps
Save-BulkCompareResults $compResultValues (Join-Path $rootFolderSource "Compare_$(((Get-Date).ToString("yyyyMMdd-HHmm"))).csv") $compareProps
if($global:chkBulkCompareSaveJson.IsChecked) {
Save-BulkCompareJsonResults $compResultValues (Join-Path $rootFolder "Compare_$(((Get-Date).ToString("yyyyMMdd-HHmm"))).json")
}
}
Write-Log "****************************************************************"
@@ -1103,6 +1162,13 @@ function Start-BulkCompareExportFolders
}
}
function Save-BulkCompareJsonResults
{
param($CompareResults, $FileName)
$CompareResults | ConvertTo-Json -Depth 50 | Out-File $FileName -Force -Encoding UTF8
}
function Save-BulkCompareResults
{
param($compResultValues, $file, $props)
@@ -1359,7 +1425,7 @@ function Add-CompareProperty
$value1 = if($value1 -eq $null) { "" } else { $value1.ToString().Trim("`"") }
$value2 = if($value2 -eq $null) { "" } else { $value2.ToString().Trim("`"") }
$compare += [PSCustomObject]@{
$compare = [PSCustomObject]@{
PropertyName = $name
Object1Value = $value1 #if($value1 -ne $null) { $value1.ToString().Trim("`"") } else { "" }
Object2Value = $value2 #if($value2 -ne $null) { $value2.ToString().Trim("`"") } else { "" }
@@ -1367,10 +1433,12 @@ function Add-CompareProperty
SubCategory = $subCategory
Match = ?? $match ($value1 -eq $value2)
}
if($skip -eq $true) {
$compare.Match = $null
}
Write-Host "Add property $($compare.PropertyName)"
$script:compareProperties += $compare
}
@@ -1474,17 +1542,19 @@ function Compare-ObjectsBasedonDocumentation
# ToDo: set this based on configuration value
$script:assignmentOutput = "simpleFullCompare"
$docObj1 = Invoke-ObjectDocumentation ([PSCustomObject]@{
$tmpObj1 = ([PSCustomObject]@{
Object = $obj1
ObjectType = $objectType
})
ObjectType = $objectType})
$docObj2 = Invoke-ObjectDocumentation ([PSCustomObject]@{
$docObj1 = Invoke-ObjectDocumentation $tmpObj1 -ObjectSeparator ($global:cbCompareMultiValueDelimiter.SelectedValue)
$tmpObj2 = ([PSCustomObject]@{
Object = $obj2
ObjectType = $objectType
})
$docObj2 = Invoke-ObjectDocumentation $tmpObj2 -ObjectSeparator ($global:cbCompareMultiValueDelimiter.SelectedValue)
$settingsValue = ?? $objectType.CompareValue "Value"
$skipBasicProperties = Get-XamlProperty $script:cmpForm "chkSkipCompareBasicProperties" "IsChecked"
@@ -1623,8 +1693,8 @@ function Compare-ObjectsBasedonDocumentation
{
$applicabilityRule2 = $docObj2.ApplicabilityRules | Where { $_.Id -eq $applicabilityRule.Id }
$applicabilityRulesAdded += $applicabilityRule.Id
$val1 = ($applicabilityRule.Rule + [environment]::NewLine + $applicabilityRule.Value)
$val2 = ($applicabilityRule2.Rule + [environment]::NewLine + $applicabilityRule2.Value)
$val1 = ($applicabilityRule.Rule + ($global:cbCompareMultiValueDelimiter.SelectedValue) + $applicabilityRule.Value)
$val2 = ($applicabilityRule2.Rule + ($global:cbCompareMultiValueDelimiter.SelectedValue) + $applicabilityRule2.Value)
Add-CompareProperty $applicabilityRule.Property $val1 $val2 $applicabilityRule.Category
}
@@ -1634,8 +1704,8 @@ function Compare-ObjectsBasedonDocumentation
if(($applicabilityRule.Id) -in $applicabilityRulesAdded) { continue }
$applicabilityRule2 = $docObj1.ApplicabilityRules | Where { $_.Id -eq $applicabilityRule.Id }
$script:applicabilityRulesAdded += $applicabilityRule.Id
$val2 = ($applicabilityRule.Rule + [environment]::NewLine + $applicabilityRule.Value)
$val1 = ($applicabilityRule2.Rule + [environment]::NewLine + $applicabilityRule2.Value)
$val2 = ($applicabilityRule.Rule + ($global:cbCompareMultiValueDelimiter.SelectedValue) + $applicabilityRule.Value)
$val1 = ($applicabilityRule2.Rule + ($global:cbCompareMultiValueDelimiter.SelectedValue) + $applicabilityRule2.Value)
Add-CompareProperty $applicabilityRule.Property $val1 $val2 $applicabilityRule.Category
}
@@ -1645,8 +1715,8 @@ function Compare-ObjectsBasedonDocumentation
{
$complianceAction2 = $docObj2.ComplianceActions | Where { $_.IdStr -eq $complianceAction.IdStr }
$complianceActionsAdded += $complianceAction.IdStr
$val1 = ($complianceAction.Action + [environment]::NewLine + $complianceAction.Schedule + [environment]::NewLine + $complianceAction.MessageTemplateId + [environment]::NewLine + $complianceAction.EmailCCIds)
$val2 = ($complianceAction2.Action + [environment]::NewLine + $complianceAction2.Schedule + [environment]::NewLine + $complianceAction2.MessageTemplateId + [environment]::NewLine + $complianceAction2.EmailCCIds)
$val1 = ($complianceAction.Action + ($global:cbCompareMultiValueDelimiter.SelectedValue) + $complianceAction.Schedule + ($global:cbCompareMultiValueDelimiter.SelectedValue) + $complianceAction.MessageTemplateId + ($global:cbCompareMultiValueDelimiter.SelectedValue) + $complianceAction.EmailCCIds)
$val2 = ($complianceAction2.Action + ($global:cbCompareMultiValueDelimiter.SelectedValue) + $complianceAction2.Schedule + ($global:cbCompareMultiValueDelimiter.SelectedValue) + $complianceAction2.MessageTemplateId + ($global:cbCompareMultiValueDelimiter.SelectedValue) + $complianceAction2.EmailCCIds)
Add-CompareProperty $complianceAction.Category $val1 $val2
}
@@ -1656,8 +1726,8 @@ function Compare-ObjectsBasedonDocumentation
if(($complianceAction.IdStr) -in $complianceActionsAdded) { continue }
$complianceAction2 = $docObj1.ComplianceActions | Where { $_.IdStr -eq $complianceAction.IdStr }
$complianceActionsAdded += $complianceAction.IdStr
$val2 = ($complianceAction.Action + [environment]::NewLine + $complianceAction.Schedule + [environment]::NewLine + $complianceAction.MessageTemplateId + [environment]::NewLine + $complianceAction.EmailCCIds)
$val1 = ($complianceAction2.Action + [environment]::NewLine + $complianceAction2.Schedule + [environment]::NewLine + $complianceAction2.MessageTemplateId + [environment]::NewLine + $complianceAction2.EmailCCIds)
$val2 = ($complianceAction.Action + ($global:cbCompareMultiValueDelimiter.SelectedValue) + $complianceAction.Schedule + ($global:cbCompareMultiValueDelimiter.SelectedValue) + $complianceAction.MessageTemplateId + ($global:cbCompareMultiValueDelimiter.SelectedValue) + $complianceAction.EmailCCIds)
$val1 = ($complianceAction2.Action + ($global:cbCompareMultiValueDelimiter.SelectedValue) + $complianceAction2.Schedule + ($global:cbCompareMultiValueDelimiter.SelectedValue) + $complianceAction2.MessageTemplateId + ($global:cbCompareMultiValueDelimiter.SelectedValue) + $complianceAction2.EmailCCIds)
Add-CompareProperty $complianceAction.Category $val1 $val2
}
@@ -1782,7 +1852,11 @@ function Invoke-SilentBatchJob
$global:cbCompareCSVDelimiter.ItemsSource = @("", ",",";","-","|")
$global:cbCompareCSVDelimiter.SelectedValue = ($settingsObj.BulkCompare | Where Name -eq "cbCompareCSVDelimiter").Value
$objectSeparator = "[ { Name: `"New line`",Value: `"$([System.Environment]::NewLine)`" }, {Name: `";`",Value: `";`" }, {Name: `"|`",Value: `"|`" }]" | ConvertFrom-Json
$global:cbCompareMultiValueDelimiter.ItemsSource = $objectSeparator
$global:cbCompareMultiValueDelimiter.SelectedValue = (Get-Setting "Compare" "ObjectSeparator" ([System.Environment]::NewLine))
Set-CompareProviderOptions $global:cbCompareProvider
Set-BatchProperties $settingsObj.BulkCompare $script:cmpForm -SkipMissingControlWarning

View File

@@ -381,7 +381,11 @@ function Get-DocumentedSettings
function Invoke-ObjectDocumentation
{
param($documentationObj)
param($documentationObj,
$ObjectSeparator,
$PropertySeparator,
$DocumentationLanguage
)
$global:intentCategories = $null
$global:catRecommendedSettings = $null
@@ -389,10 +393,11 @@ function Invoke-ObjectDocumentation
$global:cfgCategories = $null
$script:admxCategories = $null
$script:migTable = $null
$script:offlineObjects = @{}
$script:DocumentationLanguage = "en"
$script:objectSeparator = [System.Environment]::NewLine
$script:propertySeparator = ","
$script:DocumentationLanguage = ?? $DocumentationLanguage "en"
$script:objectSeparator = ?? $ObjectSeparator ([System.Environment]::NewLine)
$script:propertySeparator = ?? $PropertySeparator ","
$loadExportedInfo = $false
@@ -691,6 +696,10 @@ function Add-BasicAdditionalValues
if($obj.createdDateTime -is [DateTime])
{
$tmpDate = $obj.createdDateTime
if($tmpDate.Kind -eq "UTC")
{
$tmpDate = $tmpDate.ToLocalTime()
}
}
else
{
@@ -714,6 +723,10 @@ function Add-BasicAdditionalValues
if($obj.lastModifiedDateTime -is [DateTime])
{
$tmpDate = $obj.lastModifiedDateTime
if($tmpDate.Kind -eq "UTC")
{
$tmpDate = $tmpDate.ToLocalTime()
}
}
else
{
@@ -735,6 +748,10 @@ function Add-BasicAdditionalValues
if($obj.modifiedDateTime -is [DateTime])
{
$tmpDate = $obj.modifiedDateTime
if($tmpDate.Kind -eq "UTC")
{
$tmpDate = $tmpDate.ToLocalTime()
}
}
else
{
@@ -1037,15 +1054,26 @@ function Invoke-TranslateADMXObject
$rawValues += $rawValue
}
$status = (?: ($definitionValue.enabled -eq $true) $enabledStr $disabledStr)
$combinedValue = $status
if($values) {
$combinedValue += $script:objectSeparator + ($values -join $script:objectSeparator)
}
$combinedValueWithLabel = $status
if($valuesWithLabel) {
$combinedValueWithLabel += $script:objectSeparator + ($valuesWithLabel -join $script:objectSeparator)
}
$script:objectSettingsData += New-Object PSObject -Property @{
Name = $definitionValue.definition.displayName
Description = $definitionValue.definition.explainText
Status = $status
Value = $values -join $script:objectSeparator
CombinedValue = ($status + $script:objectSeparator + ($values -join $script:objectSeparator))
CombinedValue = $combinedValue #($status + $script:objectSeparator + ($values -join $script:objectSeparator))
ValueWithLabel = $valuesWithLabel -join $script:objectSeparator
FullValueTable = $tableValue
CombinedValueWithLabel = ($status + $script:objectSeparator + ($valuesWithLabel -join $script:objectSeparator))
CombinedValueWithLabel = $combinedValueWithLabel #($status + $script:objectSeparator + ($valuesWithLabel -join $script:objectSeparator))
RawValue = $rawValues -join $script:propertySeparator
Class = $definitionValue.definition.classType
DefinitionId = $definitionValue.definition.id
@@ -1208,14 +1236,24 @@ function Add-SettingsSetting
{
$subCategory = $null
$objCategory = $categoryDef
}
}
$settingName = ""
$settingDescription = ""
if($settingsDef.displayName) {
$settingName = $settingsDef.displayName.Trim([Environment]::NewLine).Trim('`n')
}
if($settingsDef.description) {
$settingDescription = $settingsDef.description.Trim([Environment]::NewLine).Trim('`n')
}
$settingInfo = [PSCustomObject]@{
SettingId = $settingsDef.Id
SettingKey = ""
SettingName = $settingsDef.Name
Name = $settingsDef.displayName
Description=$settingsDef.description
Name = $settingName
Description = $settingDescription
CategortyId = $objCategory.id
Category=$objCategory.displayName
CategoryDefinition=$objCategory

View File

@@ -1180,6 +1180,12 @@ function Add-CDDocumentCustomProfileProperty
}
elseif($obj.'@OData.Type' -eq "#microsoft.graph.windows10EnrollmentCompletionPageConfiguration")
{
$installProgressTimeout = $obj.installProgressTimeoutInMinutes
if($installProgressTimeout -eq 0) {
$installProgressTimeout = 60
}
$obj | Add-Member Noteproperty -Name "InstallProgressTimeout" -Value $installProgressTimeout
if($obj.selectedMobileAppIds.Count -eq 0)
{
$apps = Get-LanguageString "EnrollmentStatusScreen.Apps.useSelectedAppsAll"
@@ -2299,6 +2305,10 @@ function Invoke-CDDocumentTermsOfUse
if($obj.termsExpiration.startDateTime -is [DateTime])
{
$tmpDate = $obj.termsExpiration.startDateTime
if($tmpDate.Kind -eq "UTC")
{
$tmpDate = $tmpDate.ToLocalTime()
}
}
else
{
@@ -4154,7 +4164,17 @@ function Invoke-CDDocumentWindowsKioskConfiguration
{
try
{
$startDateObj = Get-Date $obj.windowsKioskForceUpdateSchedule.startDateTime -ErrorAction Stop
if($obj.windowsKioskForceUpdateSchedule.startDateTime -is [DateTime]) {
$startDateObj = $obj.windowsKioskForceUpdateSchedule.startDateTime
if($startDateObj.Kind -eq "UTC")
{
$startDateObj = $startDateObj.ToLocalTime()
}
}
else
{
$startDateObj = Get-Date $obj.windowsKioskForceUpdateSchedule.startDateTime -ErrorAction Stop
}
Add-CustomSettingObject ([PSCustomObject]@{
Name = Get-LanguageString "SettingDetails.kioskStartDateTime"

View File

@@ -265,7 +265,7 @@ function Invoke-MDProcessItem
foreach($prop in $global:txtMDCustomProperties.Text.Split(","))
{
# This will add language support for custom columens (or replacing existing header)
# This will add language support for custom columns (or replacing existing header)
$propInfo = $prop.Split('=')
if(($propInfo | measure).Count -gt 1)
{
@@ -312,7 +312,7 @@ function Invoke-MDProcessItem
foreach($customTable in ($documentedObj.CustomTables | Sort-Object -Property Order))
{
Add-MDTableItems $obj $objectType $documentedObj $customTable.Values $customTable.Columns $customTable.LanguageId -AddCategories -AddSubcategories
Add-MDTableItems $obj $objectType $customTable.Values $customTable.Columns $customTable.LanguageId -AddCategories -AddSubcategories
}
if(($documentedObj.Assignments | measure).Count -gt 0)

View File

@@ -575,7 +575,7 @@ function Invoke-WordProcessItem
foreach($customTable in ($documentedObj.CustomTables | Sort-Object -Property Order))
{
Add-DocTableItems $obj $objectType $documentedObj $customTable.Values $customTable.Columns $customTable.LanguageId -AddCategories -AddSubcategories
Add-DocTableItems $obj $objectType $customTable.Values $customTable.Columns $customTable.LanguageId -AddCategories -AddSubcategories
}
}
@@ -678,6 +678,10 @@ function Set-DocTableSettingsItems
$cellRow = $row
foreach($settingProp in $properties)
{
if([String]::IsNullOrEmpty($settingProp)) {
continue
}
$script:docTable.Cell($cellRow, $firstColumn).Range.Text = (Invoke-DocTranslateColumnHeader ($settingProp.Split('.')[-1]))
$propArr = $settingProp.Split('.')
@@ -779,6 +783,9 @@ function Add-DocTableItems
$i = 1
foreach($prop in $properties)
{
if([String]::IsNullOrEmpty($prop)) {
continue
}
$script:docTable.Cell(1, $i).Range.Text = (Invoke-DocTranslateColumnHeader ($prop.Split(".")[-1]))
$i++
}

View File

@@ -614,6 +614,24 @@ function Invoke-InitializeModule
Dependencies = @("ReusableSettings")
GroupId = "DeviceConfiguration"
})
Add-ViewItem (New-Object PSObject -Property @{
Title = "Inventory Policies"
Id = "InventoryPolicies"
ViewID = "IntuneGraphAPI"
API = "/deviceManagement/inventoryPolicies"
PropertiesToRemove = @('settingCount')
Permissons=@("DeviceManagementConfiguration.ReadWrite.All")
NameProperty = "Name"
ViewProperties = @("name","description","Id")
Expand="Settings"
Icon="DeviceConfiguration"
PostExportCommand = { Start-PostExportSettingsCatalog @args }
PreUpdateCommand = { Start-PreUpdateSettingsCatalog @args }
PostGetCommand = { Start-PostGetSettingsCatalog @args }
GroupId = "DeviceConfiguration"
})
Add-ViewItem (New-Object PSObject -Property @{
Title = "Role Definitions"
@@ -831,7 +849,17 @@ function Invoke-InitializeModule
Permissons = @("DeviceManagementConfiguration.ReadWrite.All")
Icon = "UpdatePolicies"
GroupId = "WinDriverUpdatePolicies"
})
})
Add-ViewItem (New-Object PSObject -Property @{
Title = "Device Categories"
Id = "DeviceCategories"
ViewID = "IntuneGraphAPI"
API = "/deviceManagement/deviceCategories"
Permissons = @("DeviceManagementConfiguration.ReadWrite.All")
GroupId = "DeviceConfiguration"
})
}
function Invoke-EMAuthenticateToMSAL
@@ -2512,7 +2540,7 @@ function Start-PostExportApplications
}
else
{
Write-Log "Cound not file encryption file"
Write-Log "Cound not find encryption file"
}
}
}

View File

@@ -1979,11 +1979,13 @@ function Add-ADMXRegClasses
{
return
}
$classDef = @"
using System.ComponentModel;
public class ADMXRegPolicyElement : INotifyPropertyChanged
$classDef = @"
using System;
using System.ComponentModel;
using System.Collections.ObjectModel;
public class ADMXRegPolicyElement : System.ComponentModel.INotifyPropertyChanged
{
public string DataType { get { return _dataType; } set { _dataType = value; NotifyPropertyChanged("DataType"); NotifyPropertyChanged("DataTypeDisplayString"); } }
private string _dataType = null;
@@ -2069,8 +2071,9 @@ function Add-ADMXRegClasses
}
}
"@
[Reflection.Assembly]::LoadWithPartialName("mscorlib") | Out-Null
[Reflection.Assembly]::LoadWithPartialName("System.ComponentModel") | Out-Null
Add-Type -TypeDefinition $classDef -IgnoreWarnings -ReferencedAssemblies @('System.ComponentModel')
Add-Type -TypeDefinition $classDef
}
#endregion

View File

@@ -129,6 +129,20 @@ function Invoke-InitializeModule
Description = "Sort the list of available tenants based on Tenant name. Updated at restart or account change"
}) "MSAL"
Add-SettingsObject (New-Object PSObject -Property @{
Title = "Use WAM for eahanced login methods"
Key = "UseWAM"
Type = "Boolean"
DefaultValue = $false
Description = "Use WAM for eahanced login methods"
}) "MSAL"
$script:MSALUseWAM = Get-SettingValue "UseWAM"
if($script:MSALUseWAM -and $PSVersionTable.PSVersion.Major -lt 7) {
Write-Log "WAM is only supported in PowerShell 7 and later. Disabling WAM" 2
$script:MSALUseWAM = $false
}
Add-MSALPrereq
}
@@ -200,6 +214,9 @@ function Set-MSALGraphEnvironment
{
$curAADEnv = $script:lstAADEnvironments | Where URL -eq $user.Environment
}
elseif($global:UseGraphEnvironment) {
$curAADEnv = $script:lstAADEnvironments | Where value -eq $global:UseGraphEnvironment
}
else
{
$curAADEnv = $script:lstAADEnvironments | Where value -eq (Get-Setting "" "MSALCloudType" "public")
@@ -207,7 +224,14 @@ function Set-MSALGraphEnvironment
if($curAADEnv.Value -eq "usGov")
{
$gccEnv = (Get-Setting "" "MSALGCCType" "gcc")
if($global:UseGCCType)
{
$gccEnv = $global:UseGCCType
}
else {
$gccEnv = (Get-Setting "" "MSALGCCType" "gcc")
}
if($gccEnv)
{
$GCCEnvObj = $script:lstGCCEnvironments | Where Value -eq $gccEnv
@@ -487,6 +511,129 @@ function Install-MSALDependencyModule
}
function Add-MSALPrereq
{
$ScriptRoot = $global:AppRootFolder
$DLLFiles = @()
if($PSVersionTable.PSVersion.Major -ge 7) {
$DLLFiles += [IO.FileInfo]($ScriptRoot + "\Bin\Microsoft.IdentityModel.Abstractions.dll")
}
else {
$DLLFiles += [IO.FileInfo]($ScriptRoot + "\Bin\6.35.0\Microsoft.IdentityModel.Abstractions.dll")
}
$DLLFiles += [IO.FileInfo]($ScriptRoot + "\Bin\Microsoft.Identity.Client.dll")
if($script:MSALUseWAM) {
$DLLFiles += [IO.FileInfo]($ScriptRoot + "\BIN\$MSALDLLPath\Microsoft.Identity.Client.Extensions.Msal.dll")
$DLLFiles += [IO.FileInfo]($ScriptRoot + "\BIN\$MSALDLLPath\Microsoft.Identity.Client.Broker.dll")
$DLLFiles += [IO.FileInfo]($ScriptRoot + "\BIN\$MSALDLLPath\Microsoft.Identity.Client.Desktop.dll")
$DLLFiles += [IO.FileInfo]($ScriptRoot + "\BIN\$MSALDLLPath\Microsoft.Identity.Client.NativeInterop.dll")
}
$DLLFiles | ForEach-Object {
$dllFile = $_
# ToDo: Unblock files
if($_.Exists) {
try {
[void][System.Reflection.Assembly]::LoadFrom($_.FullName)
Write-Log "Loaded $($_.Name) version $($_.VersionInfo.FileVersion)"
}
catch {
$loadedFile = [Appdomain]::CurrentDomain.GetAssemblies() | Where Location -like "*\$($dllFile.Name)"
if($loadedFile) {
$loadedFI = [IO.FileInfo]($loadedFile.Location)
Write-Log "Failed to load $($dllFile.Name) version $($dllFile.VersionInfo.FileVersion). File already loaded: $($loadedFI.FullName) version $($loadedFI.VersionInfo.FileVersion)" 2
}
else {
Write-LogError "Failed to load $($dllFile.Name) version $($dllFile.VersionInfo.FileVersion)" $_.Exception
}
}
}
else {
Write-LogError "Microsoft.Identity file not found: $($_.FullName)"
}
}
if (-not ("TokenCacheHelperEx" -as [type]))
{
[System.Collections.Generic.List[string]] $RequiredAssemblies = New-Object System.Collections.Generic.List[string]
foreach($file in $DLLFiles) {
$RequiredAssemblies.Add($file.FullName)
}
$RequiredAssemblies.Add('System.Security.dll')
$RequiredAssemblies.Add('mscorlib.dll')
if($PSVersionTable.PSVersion.Major -ge 7) {
$RequiredAssemblies.Add('System.Security.Cryptography.ProtectedData.dll')
}
$RequiredAssemblies.Add('System.Threading.dll')
try
{
Add-Type -Path ($ScriptRoot + "\CS\TokenCacheHelperEx.cs") -ReferencedAssemblies $RequiredAssemblies -IgnoreWarnings
}
catch
{
Write-LogError "Failed to compile TokenCacheHelperEx. The access token will not be cached. Check write access to the CS folder and ASR policies" $_.Exception
}
}
if($script:MSALUseWAM) {
[System.Collections.Generic.List[string]] $RequiredAssemblies = New-Object System.Collections.Generic.List[string]
foreach($file in $DLLFiles) {
$RequiredAssemblies.Add($file.FullName)
}
$RequiredAssemblies.Add('mscorlib.dll')
$RequiredAssemblies.Add('System.dll')
$RequiredAssemblies.Add('System.Windows.Forms')
# Import necessary methods from user32.dll and kernel32.dll
Add-Type @"
using System;
using System.Runtime.InteropServices;
using Microsoft.Identity.Client;
//using Microsoft.Identity.Client.Desktop;
using Microsoft.Identity.Client.Broker;
using System.Windows.Forms;
public class MSALMethods
{
enum GetAncestorFlags {
GetParent = 1,
GetRoot = 2,
GetRootOwner = 3
}
[DllImport("user32.dll", ExactSpelling = true)]
public static extern IntPtr GetAncestor(IntPtr hwnd, int flags);
[DllImport("kernel32.dll")]
public static extern IntPtr GetConsoleWindow();
// This is your window handle!
public static IntPtr GetConsoleOrTerminalWindow()
{
IntPtr consoleHandle = GetConsoleWindow();
IntPtr handle = GetAncestor(consoleHandle, (int)GetAncestorFlags.GetRootOwner );
return handle;
}
public static void AddParentActivirtyOrWindow(PublicClientApplicationBuilder appBuilder)
{
appBuilder.WithParentActivityOrWindow(GetConsoleOrTerminalWindow);
}
public static void AddWithBroker(PublicClientApplicationBuilder appBuilder, BrokerOptions options)
{
appBuilder.WithBroker(options);
}
}
"@ -ReferencedAssemblies $RequiredAssemblies -IgnoreWarnings
}
}
function Add-MSALPrereq_old
{
$msalPath = ""
@@ -565,7 +712,15 @@ function Add-MSALPrereq
$RequiredAssemblies.Add($msalPath)
$script:msalFile = $msalPath
}
$RequiredAssemblies.Add('System.Security.dll')
$RequiredAssemblies.Add('mscorlib.dll')
if($PSVersionTable.PSVersion.Major -ge 7)
{
$RequiredAssemblies.Add('System.Security.Cryptography.ProtectedData.dll')
}
$RequiredAssemblies.Add('System.Threading.dll')
try
{
@@ -586,6 +741,10 @@ function Connect-MSALClientApp
if(-not $script:MSALApp)
{
if($global:UseGraphEnvironment) {
Set-MSALGraphEnvironment $null $null
}
$authority = "https://login.microsoftonline.com/$tenantId"
#$redirectUri = "http://localhost"
@@ -747,7 +906,7 @@ function Get-MSALApp
{
param($appInfo, $loginHint)
$msalApp = $script:MSALAllApps | Where { $_.ClientId -eq $appInfo.ClientID -and (-not $appInfo.RedirectUri -or $_.AppConfig.RedirectUri -eq $appInfo.RedirectUri)}
$msalApp = $script:MSALAllApps | Where { $_.AppConfig.ClientId -eq $appInfo.ClientID -and (-not $appInfo.RedirectUri -or $_.AppConfig.RedirectUri -eq $appInfo.RedirectUri)}
$tenant = ?? $appInfo.TenantId "organizations"
@@ -770,14 +929,21 @@ function Get-MSALApp
$appBuilder = [Microsoft.Identity.Client.PublicClientApplicationBuilder]::Create($appInfo.ClientID)
[void]$appBuilder.WithAuthority($authority)
#if($appInfo.TenantId) { [void]$appBuilder.WithAuthority("https://$((?? $loginHint.Environment (Get-MSALLoginEnvironment)))/$($appInfo.TenantId)/") }
#elseif ($appInfo.Authority) { [void]$appBuilder.WithAuthority($appInfo.Authority) }
if($appInfo.RedirectUri) { [void]$appBuilder.WithRedirectUri($appInfo.RedirectUri) }
[void] $appBuilder.WithClientName("CloudAPIPowerShellManagement")
[void] $appBuilder.WithClientVersion($PSVersionTable.PSVersion)
if($script:MSALUseWAM) {
[MSALMethods]::AddParentActivirtyOrWindow($appBuilder)
$options = [Microsoft.Identity.Client.BrokerOptions]::new([Microsoft.Identity.Client.BrokerOptions+OperatingSystems]::Windows)
$options.Title = "Intune Manager"
[MSALMethods]::AddWithBroker($appBuilder, $options)
}
Add-MSALProxy $appBuilder
# Ceck if correct version...
@@ -908,8 +1074,6 @@ function Connect-MSALUser
Add-MSALPrereq
}
$curTicks = $global:MSALToken.ExpiresOn.LocalDateTime.Ticks
$currentLoggedInUserApp = ($global:MSALToken.Account.HomeAccountId.Identifier + $global:MSALToken.TenantId + $global:MSALApp.ClientId)
$currentLoggedInUserId = $global:MSALToken.Account.HomeAccountId.Identifier
if($Interactive -eq $true)
@@ -1014,15 +1178,6 @@ function Connect-MSALUser
Clear-MSALCurentUserVaiables
return
}
if($authResult -and $authResult.ExpiresOn.LocalDateTime.Ticks -ne $curTicks)
{
Write-Log "$($authResult.Account.UserName) authenticated successfully (Silent). CorrelationId: $($global:MSALToken.CorrelationId)"
}
else
{
Write-LogDebug "$($authResult.Account.UserName) authenticated successfully (Silent). CorrelationId: $($global:MSALToken.CorrelationId)"
}
#AADSTS65001
if($script:authenticationFailure.Classification -eq "ConsentRequired")
@@ -1113,6 +1268,10 @@ function Connect-MSALUser
{
Write-Log "Login hint: $loginHintName"
[void]$AquireTokenObj.WithLoginHint($loginHintName)
[void]$AquireTokenObj.WithPrompt([Microsoft.Identity.Client.Prompt]::NoPrompt)
}
else {
[void]$AquireTokenObj.WithPrompt([Microsoft.Identity.Client.Prompt]::SelectAccount)
}
if($script:authenticationFailure.Claims)
@@ -1133,11 +1292,6 @@ function Connect-MSALUser
Write-Log "Interactive login with Consent prompt"
[void]$aquireTokenObj.WithPrompt([Microsoft.Identity.Client.Prompt]::Consent)
}
elseif(-not $loginHintName)
{
Write-Log "Interactive login with Select account prompt"
[void]$AquireTokenObj.WithPrompt([Microsoft.Identity.Client.Prompt]::SelectAccount)
}
$authResult = Get-MsalAuthenticationToken $aquireTokenObj
if($authResult)
@@ -1146,6 +1300,31 @@ function Connect-MSALUser
}
}
if($authResult) {
$telemetry = $null
$wamTelemetry = $null
if($authResult.AuthenticationResultMetadata.Telemetry) {
try {
$telemetry = $authResult.AuthenticationResultMetadata.Telemetry | ConvertFrom-Json
if($telemetry.wam_telemetry) {
$wamTelemetry = $telemetry.wam_telemetry | ConvertFrom-Json
}
}
catch {}
}
if($authResult.AuthenticationResultMetadata.TokenSource -eq "Broker" -and $telemetry.broker_app_used -eq "true") {
Write-Log "Token received from Broker. Time (ms): $($authResult.AuthenticationResultMetadata.DurationTotalInMs). CorrelationId: $($authResult.CorrelationId)"
}
elseif($authResult.AuthenticationResultMetadata.TokenSource -eq "IdentityProvider") {
Write-Log "Token received from IdentityProvider. Time (ms) $($authResult.AuthenticationResultMetadata.DurationTotalInMs)"
}
else {
# ToDo: Change to debug
Write-Log "Token received from Cache. Time (ms) $($authResult.AuthenticationResultMetadata.DurationTotalInMs)"
}
}
if($currentLoggedInUserId -ne $authResult.Account.HomeAccountId.Identifier)
{
$script:AccessableTenants = $null
@@ -1218,22 +1397,13 @@ function Connect-MSALUser
$global:MSALToken = $authResult
if($currentLoggedInUserApp -ne ($global:MSALToken.Account.HomeAccountId.Identifier + $global:MSALToken.TenantId + $global:MSALApp.ClientId))
{
{
if($authResult)
{
Save-Setting "" "LastLoggedOnUser" $authResult.Account.UserName
Save-Setting "" "LastLoggedOnUserId" $authResult.Account.HomeAccountId.ObjectId
}
Invoke-MSALAuthenticationUpdated $authResult
<#
Write-LogDebug "User, tenant or app has changed"
Get-MSALUserInfo
if($authResult)
{
Invoke-MSALCheckObjectViewAccess $authResult
}
Invoke-ModuleFunction "Invoke-GraphAuthenticationUpdated"
#>
}
}
@@ -2161,7 +2331,7 @@ function Show-MSALDecodedToken {
{
if($prop.Name -in @("exp","iat","nbf","xms_tcdt"))
{
$value =[datetime]::new(1970, 1, 1, 0, 0, 0, 0, "UTC").AddSeconds(($tokenData.Payload."$($prop.Name)")).ToLocalTime()
$value = [datetime]::new(1970, 1, 1, 0, 0, 0, 0, [System.DateTimeKind]::Utc).AddSeconds(($tokenData.Payload."$($prop.Name)")).ToLocalTime()
}
elseif($prop.Name -in @("acrs","amr"))
{

View File

@@ -53,6 +53,33 @@ function Invoke-InitializeModule
}
)
$script:lstGraphPageSize = @(
[PSCustomObject]@{
Name = "Graph API Default"
Value = "0"
},
[PSCustomObject]@{
Name = "5"
Value = "5"
},
[PSCustomObject]@{
Name = "20"
Value = "20"
},
[PSCustomObject]@{
Name = "50"
Value = "50"
},
[PSCustomObject]@{
Name = "100"
Value = "100"
},
[PSCustomObject]@{
Name = "All"
Value = "All"
}
)
# Make sure MS Graph settings are added before exiting before App Id and Tenant Id is missing
Write-Log "Add settings and menu items"
@@ -239,6 +266,14 @@ function Invoke-InitializeModule
Description = "This will use production verionof graph, v1.0. Note: Thot officially supported since this can have unpredicted results. Some parts will require Beta version of Graph."
}) "GraphGeneral"
Add-SettingsObject (New-Object PSObject -Property @{
Title = "API Page Size"
Key = "GraphPageSize"
Type = "List"
ItemsSource = $script:lstGraphPageSize
DefaultValue = "20"
Description = "How many items load at a time"
}) "GraphGeneral"
}
function Get-GraphAppInfo
@@ -558,7 +593,9 @@ function Get-GraphObjects
[switch]
$SingleObject,
[string]
$filter)
$filter,
[int]
$pageSize = -1)
$params = @{}
if($objectType.ODataMetadata)
@@ -593,6 +630,10 @@ function Get-GraphObjects
{
#Use default page size or use below for a specific page size for testing
#$params.Add("pageSize",5) #!!!
if ($pageSize -gt 0)
{
$params.Add("pageSize", $pageSize)
}
}
elseif($SingleObject -ne $true -and $SinglePage -ne $true)
{
@@ -780,7 +821,30 @@ function Show-GraphObjects
$script:nextGraphPage = $null
[array]$graphObjects = Get-GraphObjects -property $global:curObjectType.ViewProperties -objectType $global:curObjectType -SinglePage -Filter $filter
$params = @{}
$pageSize = 0
$tmpPageSize = Get-SettingValue "GraphPageSize"
if ($tmpPageSize -eq "All")
{
$params.Add("AllPages", $true)
}else
{
if($tmpPageSize) {
try {
$pageSize = [int]$tmpPageSize
}
catch {}
}
if($pageSize -gt 0)
{
$params.Add("PageSize", $pageSize)
}
$params.Add("SinglePage", $true)
}
[array]$graphObjects = Get-GraphObjects -property $global:curObjectType.ViewProperties -objectType $global:curObjectType -Filter $filter @params
$dgObjects.AutoGenerateColumns = $false
$dgObjects.Columns.Clear()
@@ -1051,6 +1115,34 @@ function Start-GraphPreImport
}
}
function Remove-GraphODataProperties
{
param($obj)
# Remove OData properties
foreach($odataProp in ($obj.PSObject.Properties | Where { $_.Name -like "*@*" }))
{
$removeProperties += $odataProp.Name
}
foreach($prop in $removeProperties)
{
Remove-Property $obj $prop
}
foreach($prop in ($obj.PSObject.Properties))
{
if($obj."$($prop.Name)"."@odata.type")
{
foreach($childObj in ($obj."$($prop.Name)"))
{
Remove-GraphODataProperties $childObj
}
}
}
}
function Get-GraphMetaData
{
if(-not $global:metaDataXML)
@@ -4148,9 +4240,10 @@ function local:Add-ObjectColumnInfoClass
}
$classDef = @"
using System;
using System.ComponentModel;
public class ObjectColumnInfo : INotifyPropertyChanged
public class ObjectColumnInfo : System.ComponentModel.INotifyPropertyChanged
{
public string Property { get { return _property; } set { _property = value; NotifyPropertyChanged("Property"); } }
private string _property = null;
@@ -4176,8 +4269,14 @@ function local:Add-ObjectColumnInfoClass
}
"@
[Reflection.Assembly]::LoadWithPartialName("System.ComponentModel") | Out-Null
Add-Type -TypeDefinition $classDef -IgnoreWarnings -ReferencedAssemblies @('System.ComponentModel')
try {
Add-Type -TypeDefinition $classDef -IgnoreWarnings #-ReferencedAssemblies @('System.ComponentModel')
}
catch
{
Write-LogError "Failed to add type ObjectColumnInfo" $_.Exception
}
}
function Local:Show-ObjectDefaultColumnsSettings