This commit is contained in:
Mikael Karlsson
2022-04-26 21:49:54 +10:00
parent 46435b5717
commit 4571341763
56 changed files with 101162 additions and 79376 deletions

View File

@@ -20,11 +20,13 @@ $global:documentationProviders = @()
function Get-ModuleVersion
{
'1.1.0'
'1.2.0'
}
function Invoke-InitializeModule
{
$script:alwaysUseMigTableForTranslation = $false
# Make sure we add the default Output types
Add-OutputType
@@ -43,14 +45,20 @@ function Invoke-InitializeModule
Schedule="ScheduledAction.List.schedule"
MessageTemplate="ScheduledAction.Notification.messageTemplate"
EmailCC="ScheduledAction.Notification.additionalRecipients"
Filter="AssignmentFilters.assignmentFilterColumnHeader"
Rule="ApplicabilityRules.GridLabel.Rule"
ValueWithLabel="TableHeaders.value"
Status="TableHeaders.status"
CombinedValueWithLabel="TableHeaders.value"
CombinedValue="TableHeaders.value"
useDeviceLicensing="TableHeaders.licenseType"
#filterMode="Filter mode" # Not in any string file yet
Filter="AppResources.AppSettingsUx.assignmentFilterColumnHeader"
filterMode="AppResources.AppSettingsUx.assignmentFilterTypeColumnHeader"
deliveryOptimizationPriority="AppResources.AppSettingsUx.deliveryOptimizationPriorityHeader"
startTimeColumnLabel="AppResources.AppSettingsUx.startTimeColumnLabel"
installTimeSettings="AppResources.AppSettingsUx.deadlineTimeColumnLabel"
restartSettings="AppResources.AppSettingsUx.restartGracePeriodHeader"
notifications="AppResources.AppSettingsUx.assignmentToast"
Settings="TableHeaders.settings"
}
}
@@ -199,7 +207,7 @@ function Get-ObjectDocumentation
$status = $null
$inputType = "Settings"
if(-not $script:scopeTags)
if(-not $script:scopeTags -and $script:offlineDocumentation -ne $true)
{
$script:scopeTags = (Invoke-GraphRequest -Url "/deviceManagement/roleScopeTags").Value
}
@@ -209,7 +217,7 @@ function Get-ObjectDocumentation
$script:currentObject = $obj
$script:languageStrings = $null
$script:CurrentSubCategory = $null
$script:objectBasicInfo = @()
$script:objectSettingsData = @()
@@ -587,19 +595,68 @@ function Add-BasicAdditionalValues
if($obj.createdDateTime)
{
$tmpDate = ([DateTime]::Parse($obj.createdDateTime))
Add-BasicPropertyValue (Get-LanguageString "Inputs.createdDateTime") "$($tmpDate.ToLongDateString()) $($tmpDate.ToLongTimeString())"
try
{
if($obj.createdDateTime -is [DateTime])
{
$tmpDate = $obj.createdDateTime
}
else
{
$tmpDate = ([DateTime]::Parse($obj.createdDateTime))
}
$tmpDateStr = "$($tmpDate.ToLongDateString()) $($tmpDate.ToLongTimeString())"
}
catch
{
Write-Log "Failed to parse date from $($obj.createdDateTime) (Object type: $($obj.createdDateTime.GetType().Name))" 2
$tmpDateStr = $obj.createdDateTime
}
Add-BasicPropertyValue (Get-LanguageString "Inputs.createdDateTime") $tmpDateStr
}
if($obj.lastModifiedDateTime)
{
$tmpDate = ([DateTime]::Parse($obj.lastModifiedDateTime))
Add-BasicPropertyValue (Get-LanguageString "TableHeaders.lastModified") "$($tmpDate.ToLongDateString()) $($tmpDate.ToLongTimeString())"
try
{
if($obj.lastModifiedDateTime -is [DateTime])
{
$tmpDate = $obj.lastModifiedDateTime
}
else
{
$tmpDate = ([DateTime]::Parse($obj.lastModifiedDateTime))
}
$tmpDateStr = "$($tmpDate.ToLongDateString()) $($tmpDate.ToLongTimeString())"
}
catch
{
Write-Log "Failed to parse date from $($obj.lastModifiedDateTime) (Object type: $($obj.lastModifiedDateTime.GetType().Name))" 2
$tmpDateStr = $obj.lastModifiedDateTime
}
Add-BasicPropertyValue (Get-LanguageString "TableHeaders.lastModified") $tmpDateStr
}
elseif($obj.modifiedDateTime)
{
$tmpDate = ([DateTime]::Parse($obj.modifiedDateTime))
Add-BasicPropertyValue (Get-LanguageString "TableHeaders.lastModified") "$($tmpDate.ToLongDateString()) $($tmpDate.ToLongTimeString())"
try
{
if($obj.modifiedDateTime -is [DateTime])
{
$tmpDate = $obj.modifiedDateTime
}
else
{
$tmpDate = ([DateTime]::Parse($obj.modifiedDateTime))
}
$tmpDateStr = "$($tmpDate.ToLongDateString()) $($tmpDate.ToLongTimeString())"
}
catch
{
Write-Log "Failed to parse date from $($obj.modifiedDateTime) (Object type: $($obj.modifiedDateTime.GetType().Name))" 2
$tmpDateStr = $obj.modifiedDateTime
}
Add-BasicPropertyValue (Get-LanguageString "TableHeaders.lastModified") $tmpDateStr
}
if($obj.version)
@@ -1829,7 +1886,11 @@ function Invoke-TranslateSection
$useParentProp = $true
# Use $script:currentObject since $obj could be a property on the original object
# Cert links are always specified on the main object
$cert = Invoke-GraphRequest -URL $script:currentObject."$($prop.entityKey)@odata.navigationLink" -ODataMetadata "minimal" -NoError
$cert = $null
if($script:offlineDocumentation -ne $true)
{
$cert = Invoke-GraphRequest -URL $script:currentObject."$($prop.entityKey)@odata.navigationLink" -ODataMetadata "minimal" -NoError
}
if($cert)
{
if($cert.value -is [Object[]])
@@ -1849,7 +1910,22 @@ function Invoke-TranslateSection
}
elseif($script:currentObject.'@ObjectFromFile' -eq $true)
{
$value = "##TBD - Linked Certificate"
if($script:currentObject."#CustomRef_$($prop.entityKey)")
{
$idx = $script:currentObject."#CustomRef_$($prop.entityKey)".IndexOf("|:|")
if($idx -gt -1)
{
$value = $script:currentObject."#CustomRef_$($prop.entityKey)".SubString(0,$idx)
}
else
{
$value = $script:currentObject."#CustomRef_$($prop.entityKey)"
}
}
else
{
$value = "##TBD - Linked Certificate"
}
$rawValue = $value
}
}
@@ -2242,6 +2318,17 @@ function Get-CustomChildObject
return $obj
}
function Invoke-InitDocumentation
{
foreach($docProvider in ($global:documentationProviders | Sort -Property Priority))
{
if($docProvider.InitializeDocumentation)
{
& $docProvider.InitializeDocumentation
}
}
}
function Add-CustomProfileProperties
{
param($obj)
@@ -2900,7 +2987,7 @@ function Invoke-TranslateAssignments
$groupInfo = $null
if($groupIds.Count -gt 0)
if($groupIds.Count -gt 0 -and $script:offlineDocumentation -ne $true)
{
$ht = @{}
$ht.Add("ids", @($groupIds | Unique))
@@ -2913,26 +3000,40 @@ function Invoke-TranslateAssignments
if(($null -eq $groupInfo -or ($groupInfo | measure).Count -eq 0) -and $obj."@ObjectFromFile" -eq $true -and $script:migTable)
{
### Get group info from mig table when documenting from file if there's no access to the environment
$groupInfo = $script:migTable.Objects | Where Type -eq "Group"
$groupInfo = $script:migTable.Objects | Where Type -eq "Group"
}
if($filterIds.Count -gt 0)
{
$batchInfo = @{}
$requests = @()
#{"requests":[{"id":"<FilterID>","method":"GET","url":"deviceManagement/assignmentFilters/<FilterID>?$select=displayName"}]}
foreach($filterId in $filterIds)
{
if($script:offlineDocumentation -eq $true)
{
$requests += [PSCustomObject]@{
id = $filterIds
method = "GET"
"url" = "deviceManagement/assignmentFilters/$($filterId)?`$select=displayName"
if($script:offlineObjects["AssignmentFilters"])
{
$filtersInfo = $script:offlineObjects["AssignmentFilters"] | Where { $_.Id -in $filterIds }
}
else
{
Write-Log "No assignment filters loaded for Offline documentation. Check export folder" 2
}
}
$batchInfo = @{"requests"=$requests}
$jsonBody = $batchInfo | ConvertTo-Json
else
{
$batchInfo = @{}
$requests = @()
#{"requests":[{"id":"<FilterID>","method":"GET","url":"deviceManagement/assignmentFilters/<FilterID>?$select=displayName"}]}
foreach($filterId in $filterIds)
{
$requests += [PSCustomObject]@{
id = $filterId
method = "GET"
"url" = "deviceManagement/assignmentFilters/$($filterId)?`$select=displayName"
}
}
$batchInfo = @{"requests"=$requests}
$jsonBody = $batchInfo | ConvertTo-Json
$filtersInfo = Invoke-GraphRequest -Url "/`$batch" -Content $jsonBody -Method "Post"
$filtersInfo = (Invoke-GraphRequest -Url "/`$batch" -Content $jsonBody -Method "Post").responses.body
}
}
foreach($assignment in $obj.assignments)
@@ -2987,12 +3088,12 @@ function Invoke-TranslateAssignments
$filterName = $noFilter
$filterMode = $noFilter
if($assignment.target.deviceAndAppManagementAssignmentFilterId -and $filtersInfo.responses)
if($assignment.target.deviceAndAppManagementAssignmentFilterId -and $filtersInfo)
{
$filtersObj = $filtersInfo.responses | Where Id -eq $assignment.target.deviceAndAppManagementAssignmentFilterId
if($filtersObj.body.displayName)
$filtersObj = $filtersInfo | Where Id -eq $assignment.target.deviceAndAppManagementAssignmentFilterId
if($filtersObj.displayName)
{
$filterName = $filtersObj.body.displayName
$filterName = $filtersObj.displayName
}
if($assignment.target.deviceAndAppManagementAssignmentFilterType -eq "include")
@@ -3037,6 +3138,66 @@ function Invoke-TranslateAssignments
$value = Get-LanguageString "SettingDetails.licenseTypeUser"
}
}
elseif($settingProp -eq "restartSettings" -and $null -eq $assignment.settings.$settingProp)
{
$value = Get-LanguageString "SettingDetails.disabledOption"
}
elseif($settingProp -eq "notifications")
{
$value = ?? (Get-LanguageString "AppResources.AssignmentToast.$($assignment.settings.$settingProp)") $assignment.settings.$settingProp
}
elseif($settingProp -eq "installTimeSettings")
{
$asap = Get-LanguageString "Assignment.SoftwareInstallationTime.defaultTime"
$startValue = $asap
$value = $asap
if($assignment.settings.installTimeSettings)
{
if($assignment.settings.installTimeSettings.startDateTime)
{
$instTime = Get-Date $assignment.settings.installTimeSettings.startDateTime
if($assignment.settings.installTimeSettings.useLocalTime -eq $false)
{
$hours = ($instTime.ToUniversalTime() - $instTime).Hours
$instTime = $instTime.AddHours($hours)
}
$startValue = "$($instTime.ToShortDateString()) $($instTime.ToShortTimeString())"
}
if($assignment.settings.installTimeSettings.deadlineDateTime)
{
$endTime = Get-Date $assignment.settings.installTimeSettings.deadlineDateTime
if($assignment.settings.installTimeSettings.useLocalTime -eq $false)
{
$hours = ($endTime.ToUniversalTime() - $endTime).Hours
$endTime = $endTime.AddHours($hours)
}
$value = "$($instTime.ToShortDateString()) $($instTime.ToShortTimeString())"
}
}
$assignmentSettingProps.Add("startTimeColumnLabel", $startValue)
}
elseif($settingProp -eq "deliveryOptimizationPriority")
{
$tmpStr = Get-LanguageString "AppResources.DeliveryOptimizationPriority.displayText"
if($assignment.settings.$settingProp -ne "foreground")
{
$tmpType = Get-LanguageString "AppResources.DeliveryOptimizationPriority.backgroundNormal"
}
else
{
$tmpType = Get-LanguageString "AppResources.DeliveryOptimizationPriority.foreground"
}
$value = $tmpStr -f $tmpType
}
elseif($assignment.settings.$settingProp -eq "notConfigured")
{
$value = Get-LanguageString "BooleanActions.notConfigured"
}
else
{
$value = $assignment.settings.$settingProp
@@ -3389,6 +3550,9 @@ function Show-DocumentationForm
$txtDocumentationRawData.Text = ""
$script:offlineDocumentation = $false
$script:offlineObjects = @{}
$loadExportedInfo = $true
$script:migTable = $null
$script:scopeTags = $null
@@ -3421,6 +3585,8 @@ function Show-DocumentationForm
Get-CustomIgnoredCategories $obj
Invoke-InitDocumentation
if($global:grdDocumentObjects.Tag -eq "Objects")
{
$sourceList = @()
@@ -3532,21 +3698,20 @@ function Show-DocumentationForm
$script:migTable = ConvertFrom-Json (Get-Content $migFileName -Raw)
}
$scopeTagObjectType = $global:currentViewObject.ViewItems | Where Id -eq "ScopeTags"
if($scopeTagObjectType)
if($script:migTable.TenantId -and $script:migTable.TenantId -ne $global:organization.id)
{
$scopePath = [IO.Path]::Combine($diSource.FullName,$scopeTagObjectType.Id)
if([IO.Directory]::Exists($scopePath) -eq $false)
$script:offlineDocumentation = $true
}
if($script:offlineDocumentation -eq $true)
{
Add-DocOfflineDependecies "ScopeTags" $diSource.FullName
Add-DocOfflineDependecies "AssignmentFilters" $diSource.FullName
Add-DocOfflineObjectTypeDependecies $diSource.FullName
if($script:offlineObjects.ContainsKey("ScopeTags"))
{
Write-Log "Object path for Scope (Tags) ($($scopePath)) not found" 2
}
else
{
$scopeTagObjects = Get-GraphFileObjects $scopePath -ObjectType $scopeTagObjectType
$script:scopeTags = @(($scopeTagObjects | Select Object))
}
$script:scopeTags = @($script:offlineObjects["ScopeTags"])
}
}
}
@@ -3723,7 +3888,7 @@ function Show-DocumentationForm
}
}
}
}
}
}
if($allObjectTypeObjects.Count -gt 0)
@@ -3745,7 +3910,13 @@ function Show-DocumentationForm
Write-Status "Run PostProcess for $($global:cbDocumentationType.SelectedItem.Name)"
& $global:cbDocumentationType.SelectedItem.PostProcess
}
if($script:offlineDocumentation -eq $true)
{
# Clear the dependecy objects loaded for Offline documentation
$global:LoadedDependencyObjects = $null
}
$script:offlineDocumentation = $false
Write-Status ""
}
@@ -3797,6 +3968,18 @@ function Show-DocumentationForm
Show-ModalForm "Intune Documentation" $script:docForm -HideButtons
}
function Get-DocOfflineObjects
{
param($objectName)
if($script:offlineDocumentation -eq $false) { return }
if($script:offlineObjects.ContainsKey($objectName))
{
$script:offlineObjects[$objectName]
}
}
function Set-OutputOptionsTabStatus
{
param($control)
@@ -3828,6 +4011,42 @@ function Invoke-DocumentSelectedObjects
Show-DocumentationForm -objects $script:selectedObjects -SelectedDocuments
}
function Add-DocOfflineObjectTypeDependecies
{
param($fromFolder)
foreacH($viewItem in $global:currentViewObject.ViewItems)
{
foreach($dep in $viewItem.Dependencies)
{
Add-DocOfflineDependecies $dep $fromFolder
}
}
}
function Add-DocOfflineDependecies
{
param($objectTypeName, $fromFolder)
if($script:offlineObjects.ContainsKey($objectTypeName)) { return }
$tmpObjType = $global:currentViewObject.ViewItems | Where Id -eq $objectTypeName
if($tmpObjType)
{
$objPath = [IO.Path]::Combine($fromFolder,$tmpObjType.Id)
if([IO.Directory]::Exists($objPath) -eq $false)
{
Write-Log "Object path for $($tmpObjType.Title) ($($objPath)) not found" 2
}
else
{
$tmpObjects = Get-GraphFileObjects $objPath -ObjectType $tmpObjType
$script:offlineObjects.Add($tmpObjType.Id, @(($tmpObjects | Select Object).Object))
}
}
}
function Add-DocumentationObjects
{
param($objects)

View File

@@ -10,7 +10,7 @@ This module will also document some objects based on PowerShell functions
function Get-ModuleVersion
{
'1.1.0'
'1.2.0'
}
function Invoke-InitializeModule
@@ -18,6 +18,7 @@ function Invoke-InitializeModule
Add-DocumentationProvicer ([PSCustomObject]@{
Name="Custom"
Priority = 1000 # The priority of the Provider. Lower number has higher priority.
InitializeDocumentation = { Initialize-CDDocumentation @args }
DocumentObject = { Invoke-CDDocumentObject @args }
GetCustomProfileValue = { Add-CDDocumentCustomProfileValue @args }
GetCustomChildObject = { Get-CDDocumentCustomChildObjet @args }
@@ -27,6 +28,12 @@ function Invoke-InitializeModule
})
}
function Initialize-CDDocumentation
{
$script:allTenantApps = $null
$script:allTermsOfUse = $null
}
function Invoke-CDDocumentObject
{
param($documentationObj)
@@ -42,6 +49,13 @@ function Invoke-CDDocumentObject
Properties = @("Name","Value","Category","SubCategory") #,"RawValue","Description"
}
}
elseif($type -eq '#microsoft.graph.agreement')
{
Invoke-CDDocumentTermsOfUse $documentationObj
return [PSCustomObject]@{
Properties = @("Name","Value") #,"RawValue","Description"
}
}
elseif($type -eq '#microsoft.graph.countryNamedLocation')
{
Invoke-CDDocumentCountryNamedLocation $documentationObj
@@ -116,7 +130,7 @@ function Get-CDAllCloudApps
{
if(-not $script:allCloudApps)
{
$script:allCloudApps =(Invoke-GraphRequest -url "/servicePrincipals?`$select=displayName,appId&top=999" -ODataMetadata "minimal").value
$script:allCloudApps = (Invoke-GraphRequest -url "/servicePrincipals?`$select=displayName,appId&top=999" -ODataMetadata "minimal").value
}
$script:allCloudApps
}
@@ -125,7 +139,11 @@ function Get-CDAllTenantApps
{
if(-not $script:allTenantApps)
{
$script:allTenantApps =(Invoke-GraphRequest -url "/deviceAppManagement/mobileApps?`$select=displayName,id&top=999" -ODataMetadata "minimal").value
$script:allTenantApps = Get-DocOfflineObjects "Applications"
if(-not $script:allTenantApps)
{
$script:allTenantApps =(Invoke-GraphRequest -url "/deviceAppManagement/mobileApps?`$select=displayName,id&top=999" -ODataMetadata "minimal").value
}
}
$script:allTenantApps
}
@@ -750,13 +768,26 @@ function Add-CDDocumentCustomProfileProperty
{
if($obj.authenticationMethod -ne "derivedCredential")
{
$idCert = Invoke-GraphRequest -URL $obj."identityCertificateForClientAuthentication@odata.navigationLink" -ODataMetadata "minimal" -NoError
if($obj."#CustomRef_identityCertificateForClientAuthentication" -and $obj.'@ObjectFromFile' -eq $true)
{
$idCert = $obj."#CustomRef_identityCertificateForClientAuthentication"
$idx = $idCert.IndexOf("|:|")
if($idx -gt -1)
{
$idCertType = $idCert.SubString($idx + 3)
}
}
else
{
$idCert = Invoke-GraphRequest -URL $obj."identityCertificateForClientAuthentication@odata.navigationLink" -ODataMetadata "minimal" -NoError
$idCertType = $idCert.'@OData.Type'
}
if($idCert.'@OData.Type' -like "*Pkcs*")
if($idCertType -like "*Pkcs*")
{
$clientCertType = "PKCS certificate"
}
elseif($idCert.'@OData.Type' -like "*SCEP*")
elseif($idCertType -like "*SCEP*")
{
$clientCertType = "SCEP certificate"
}
@@ -1102,6 +1133,7 @@ function Add-CDDocumentCustomProfileProperty
$supersededApps = @()
if($obj.dependentAppCount -gt 0 -or $obj.supersededAppCount -gt 0)
{
# ToDo: Add support for Offline documentation
$relationships = (Invoke-GraphRequest -Url "/deviceAppManagement/mobileApps/$($obj.Id)/relationships?`$filter=targetType%20eq%20microsoft.graph.mobileAppRelationshipType%27child%27").value
foreach($rel in $relationships)
{
@@ -1187,6 +1219,11 @@ function Add-CDDocumentCustomProfileProperty
}
}
elseif($obj.'@OData.Type' -eq "#microsoft.graph.windows10TeamGeneralConfiguration")
{
$obj | Add-Member Noteproperty -Name "syntheticAzureOperationalInsightsEnabled" -Value ($obj.azureOperationalInsightsBlockTelemetry -eq $false)
$obj | Add-Member Noteproperty -Name "syntheticMaintenanceWindowEnabled" -Value ($obj.maintenanceWindowBlocked -eq $false)
}
if(($obj.PSObject.Properties | where Name -eq "securityRequireSafetyNetAttestationBasicIntegrity") -and
($obj.PSObject.Properties | where Name -eq "securityRequireSafetyNetAttestationCertifiedDevice"))
@@ -1478,7 +1515,7 @@ function Invoke-CDDocumentCountryNamedLocation
$countryList = @()
foreach($country in $obj.countriesAndRegions)
{
$countryList += Get-LanguageString "Countries.$($country.ToLower())"
$countryList += Get-LanguageString "AzureIAMCommon.CountryNames.countryName$($country.ToLower())"
}
Add-CustomSettingObject ([PSCustomObject]@{
@@ -1525,6 +1562,117 @@ function Invoke-CDDocumentIPNamedLocation
})
}
# Document Terms of Use
function Invoke-CDDocumentTermsOfUse
{
param($documentationObj)
$obj = $documentationObj.Object
$objectType = $documentationObj.ObjectType
$script:objectSeparator = ?? $global:cbDocumentationObjectSeparator.SelectedValue ([System.Environment]::NewLine)
$script:propertySeparator = ?? $global:cbDocumentationPropertySeparator.SelectedValue ","
$offLabel = Get-LanguageString "SettingDetails.offOption"
$onLabel = Get-LanguageString "SettingDetails.onOption"
###################################################
# Basic info
###################################################
Add-BasicPropertyValue (Get-LanguageString "SettingDetails.nameName") $obj.displayName
Add-BasicPropertyValue (Get-LanguageString "TableHeaders.configurationType") (Get-LanguageString "AzureIAM.menuItemTermsOfUse")
Add-CustomSettingObject ([PSCustomObject]@{
Name = Get-LanguageString "TermsOfUse.Wizard.agreementIsViewingBeforeAcceptanceRequiredLabel"
Value = ?: $obj.isViewingBeforeAcceptanceRequired $onLabel $offLabel
Category = $null
SubCategory = $null
EntityKey = "isViewingBeforeAcceptanceRequired"
})
Add-CustomSettingObject ([PSCustomObject]@{
Name = Get-LanguageString "TermsOfUse.Wizard.agreementIsPerDeviceAcceptanceRequiredLabel"
Value = ?: $obj.isPerDeviceAcceptanceRequired $onLabel $offLabel
Category = $null
SubCategory = $null
EntityKey = "isPerDeviceAcceptanceRequired"
})
Add-CustomSettingObject ([PSCustomObject]@{
Name = Get-LanguageString "TermsOfUse.Wizard.isAcceptanceExpirationEnabledLabel"
Value = ?: $obj.termsExpiration $onLabel $offLabel
Category = $null
SubCategory = $null
EntityKey = "isAcceptanceExpirationEnabledLabel"
})
if($obj.termsExpiration.startDateTime)
{
try
{
if($obj.termsExpiration.startDateTime -is [DateTime])
{
$tmpDate = $obj.termsExpiration.startDateTime
}
else
{
$tmpDate = ([DateTime]::Parse($obj.termsExpiration.startDateTime))
}
$tmpDateStr = ($tmpDate).ToShortDateString()
}
catch
{
Write-Log "Failed to parse date from string $($obj.termsExpiration.startDateTime)" 2
$tmpDateStr = $obj.termsExpiration.startDateTime
}
Add-CustomSettingObject ([PSCustomObject]@{
Name = Get-LanguageString "TermsOfUse.Wizard.acceptanceExpirationStartDateTimeLabel"
Value = $tmpDateStr
Category = $null
SubCategory = $null
EntityKey = "startDateTime"
})
if($obj.termsExpiration.frequency -eq "P365D")
{
$value = Get-LanguageString "TermsOfUse.AcceptanceExpirationFrequency.annually"
}
elseif($obj.termsExpiration.frequency -eq "P180D")
{
$value = Get-LanguageString "TermsOfUse.AcceptanceExpirationFrequency.biannually"
}
elseif($obj.termsExpiration.frequency -eq "P30D")
{
$value = Get-LanguageString "TermsOfUse.AcceptanceExpirationFrequency.monthly"
}
elseif($obj.termsExpiration.frequency -eq "P90D")
{
$value = Get-LanguageString "TermsOfUse.AcceptanceExpirationFrequency.quarterly"
}
Add-CustomSettingObject ([PSCustomObject]@{
Name = Get-LanguageString "TermsOfUse.Wizard.acceptanceExpirationFrequencyLabel"
Value = $value
Category = $null
SubCategory = $null
EntityKey = "frequency"
})
}
if($null -ne $obj.userReacceptRequiredFrequency)
{
$days = Get-DurationValue $obj.userReacceptRequiredFrequency
Add-CustomSettingObject ([PSCustomObject]@{
Name = Get-LanguageString "TermsOfUse.Wizard.acceptanceDurationLabel"
Value = $days
Category = $null
SubCategory = $null
EntityKey = "userReacceptRequiredFrequency"
})
}
}
# Document Conditional Access policy
function Invoke-CDDocumentConditionalAccess
{
@@ -1540,7 +1688,9 @@ function Invoke-CDDocumentConditionalAccess
# Basic info
###################################################
Add-BasicDefaultValues $obj $objectType
#Add-BasicDefaultValues $obj $objectType
Add-BasicPropertyValue (Get-LanguageString "SettingDetails.nameName") $obj.displayName
Add-BasicPropertyValue (Get-LanguageString "TableHeaders.configurationType") (Get-LanguageString "AzureIAM.conditionalAccessBladeTitle")
if($obj.state -eq "enabledForReportingButNotEnforced")
{
@@ -1590,6 +1740,7 @@ function Invoke-CDDocumentConditionalAccess
$body = $ht | ConvertTo-Json
# ToDo: Get from MigFile for Offline
$idInfo = (Invoke-GraphRequest -Url "/directoryObjects/getByIds?`$select=displayName,id" -Content $body -Method "Post").Value
}
@@ -1719,6 +1870,7 @@ function Invoke-CDDocumentConditionalAccess
$idObj = $idInfo | Where Id -eq $id
$tmpObjs += ?? $idObj.displayName $id
}
Add-CustomSettingObject ([PSCustomObject]@{
Name = $category
Value = $tmpObjs -join $script:objectSeparator
@@ -1916,8 +2068,12 @@ function Invoke-CDDocumentConditionalAccess
if(-not $script:allNamedLocations -and ($obj.conditions.locations.includeLocations.Count -gt 0 -or $obj.conditions.locations.excludeLocations.Count))
{
# Might be better to get them one by one
$script:allNamedLocations = (Invoke-GraphRequest -url "/identity/conditionalAccess/namedLocations?`$select=displayName,Id&top=999" -ODataMetadata "minimal").value
$script:allNamedLocations = Get-DocOfflineObjects "NamedLocations"
if(-not $script:allNamedLocations)
{
# Might be better to get them one by one
$script:allNamedLocations = (Invoke-GraphRequest -url "/identity/conditionalAccess/namedLocations?`$select=displayName,Id&top=999" -ODataMetadata "minimal").value
}
if(-not $script:allNamedLocations) { $script:allNamedLocations = @()}
elseif($script:allNamedLocations -isnot [Object[]]) { $script:allNamedLocations = @($script:allNamedLocations) }
@@ -1927,6 +2083,17 @@ function Invoke-CDDocumentConditionalAccess
}
}
if(-not $script:allTermsOfUse -and (($obj.grantControls.termsOfUse | measure).Count -gt 0))
{
$script:allTermsOfUse = Get-DocOfflineObjects "TermsOfUse"
if(-not $script:allTermsOfUse)
{
$script:allTermsOfUse = (Invoke-GraphRequest -url "/identityGovernance/termsOfUse/agreements?`$select=displayName,Id&top=999" -ODataMetadata "minimal").value
}
if(-not $script:allTermsOfUse ) { $script:allTermsOfUse = @()}
elseif($script:allTermsOfUse -isnot [Object[]]) { $script:allTermsOfUse = @($script:allTermsOfUse ) }
}
if($obj.conditions.locations.includeLocations.Count -gt 0)
{
$tmpObjs = @()
@@ -2056,82 +2223,103 @@ function Invoke-CDDocumentConditionalAccess
EntityKey = "policyControl"
})
if(($obj.grantControls.builtInControls | Where { $_ -eq "block"}))
if($null -eq (($obj.grantControls.builtInControls | Where { $_ -eq "block"}) ))
{
if(($obj.grantControls.builtInControls | Where { $_ -eq "mfa"}))
if(($obj.grantControls.builtInControls | measure).Count -gt 0)
{
Add-CustomSettingObject ([PSCustomObject]@{
Name = Get-LanguageString "AzureIAM.policyControlMfaChallengeDisplayedName"
Value = Get-LanguageString "Inputs.enabled"
Category = $category
SubCategory = ""
EntityKey = "mfa"
})
if(($obj.grantControls.builtInControls | Where { $_ -eq "mfa"}))
{
Add-CustomSettingObject ([PSCustomObject]@{
Name = Get-LanguageString "AzureIAM.policyControlMfaChallengeDisplayedName"
Value = Get-LanguageString "Inputs.enabled"
Category = $category
SubCategory = ""
EntityKey = "mfa"
})
}
if(($obj.grantControls.builtInControls | Where { $_ -eq "compliantDevice"}))
{
Add-CustomSettingObject ([PSCustomObject]@{
Name = Get-LanguageString "AzureIAM.policyControlCompliantDeviceDisplayedName"
Value = Get-LanguageString "Inputs.enabled"
Category = $category
SubCategory = ""
EntityKey = "compliantDevice"
})
}
if(($obj.grantControls.builtInControls | Where { $_ -eq "domainJoinedDevice"}))
{
Add-CustomSettingObject ([PSCustomObject]@{
Name = Get-LanguageString "AzureIAM.policyControlRequireDomainJoinedDisplayedName"
Value = Get-LanguageString "Inputs.enabled"
Category = $category
SubCategory = ""
EntityKey = "domainJoinedDevice"
})
}
if(($obj.grantControls.builtInControls | Where { $_ -eq "approvedApplication"}))
{
Add-CustomSettingObject ([PSCustomObject]@{
Name = Get-LanguageString "AzureIAM.policyControlRequireMamDisplayedName"
Value = Get-LanguageString "Inputs.enabled"
Category = $category
SubCategory = ""
EntityKey = "approvedApplication"
})
}
if(($obj.grantControls.builtInControls | Where { $_ -eq "compliantApplication"}))
{
Add-CustomSettingObject ([PSCustomObject]@{
Name = Get-LanguageString "AzureIAM.policyControlRequireCompliantAppDisplayedName"
Value = Get-LanguageString "Inputs.enabled"
Category = $category
SubCategory = ""
EntityKey = "compliantApplication"
})
}
if(($obj.grantControls.builtInControls | Where { $_ -eq "passwordChange"}))
{
Add-CustomSettingObject ([PSCustomObject]@{
Name = Get-LanguageString "AzureIAM.policyControlRequiredPasswordChangeDisplayedName"
Value = Get-LanguageString "Inputs.enabled"
Category = $category
SubCategory = ""
EntityKey = "passwordChange"
})
}
}
if(($obj.grantControls.builtInControls | Where { $_ -eq "compliantDevice"}))
if(($obj.grantControls.termsOfUse | measure).Count -gt 0)
{
$termsOfUse = @()
foreach($tmpId in $obj.grantControls.termsOfUse)
{
$touObj = $script:allTermsOfUse | Where Id -eq $tmpId
$termsOfUse += ?? $touObj.displayName $tmpId
}
Add-CustomSettingObject ([PSCustomObject]@{
Name = Get-LanguageString "AzureIAM.policyControlCompliantDeviceDisplayedName"
Value = Get-LanguageString "Inputs.enabled"
Name = Get-LanguageString "AzureIAM.menuItemTermsOfUse"
Value = $termsOfUse -join $script:objectSeparator
Category = $category
SubCategory = ""
EntityKey = "compliantDevice"
})
EntityKey = "termsOfUse"
})
}
if(($obj.grantControls.builtInControls | Where { $_ -eq "domainJoinedDevice"}))
{
Add-CustomSettingObject ([PSCustomObject]@{
Name = Get-LanguageString "AzureIAM.policyControlRequireDomainJoinedDisplayedName"
Value = Get-LanguageString "Inputs.enabled"
Category = $category
SubCategory = ""
EntityKey = "domainJoinedDevice"
})
}
if(($obj.grantControls.builtInControls | Where { $_ -eq "approvedApplication"}))
{
Add-CustomSettingObject ([PSCustomObject]@{
Name = Get-LanguageString "AzureIAM.policyControlRequireMamDisplayedName"
Value = Get-LanguageString "Inputs.enabled"
Category = $category
SubCategory = ""
EntityKey = "approvedApplication"
})
}
if(($obj.grantControls.builtInControls | Where { $_ -eq "compliantApplication"}))
{
Add-CustomSettingObject ([PSCustomObject]@{
Name = Get-LanguageString "AzureIAM.policyControlRequireCompliantAppDisplayedName"
Value = Get-LanguageString "Inputs.enabled"
Category = $category
SubCategory = ""
EntityKey = "compliantApplication"
})
}
if(($obj.grantControls.builtInControls | Where { $_ -eq "passwordChange"}))
{
Add-CustomSettingObject ([PSCustomObject]@{
Name = Get-LanguageString "AzureIAM.policyControlRequiredPasswordChangeDisplayedName"
Value = Get-LanguageString "Inputs.enabled"
Category = $category
SubCategory = ""
EntityKey = "passwordChange"
})
}
Add-CustomSettingObject ([PSCustomObject]@{
Name = Get-LanguageString "AzureIAM.descriptionContentForControlsAndOr"
Value = Get-LanguageString "AzureIAM.$((?: ($obj.grantControls.operator -eq "OR") "requireOneControlText" "requireAllControlsText"))"
Category = $category
SubCategory = ""
EntityKey = "grantOperator"
})
}
})
}
###################################################
# Session
@@ -2644,12 +2832,11 @@ function Invoke-CDDocumentAssignmentFilter
$label = Get-LanguageString "ApplicabilityRules.GridLabel.rule"
# "Rules" is not in the translation file
$category = "Rules"
$category = Get-LanguageString "SettingDetails.rules"
Add-CustomSettingObject ([PSCustomObject]@{
Name = $label
Value = $obj.rule
Value = $obj.rule
EntityKey = "rule"
Category = $category
SubCategory = $null

View File

@@ -3,7 +3,7 @@
#https://docs.microsoft.com/en-us/office/vba/api/overview/word
function Get-ModuleVersion
{
'1.1.0'
'1.2.0'
}
function Invoke-InitializeModule
@@ -31,32 +31,7 @@ function Invoke-InitializeModule
Process = { Invoke-WordProcessItem @args }
PostProcess = { Invoke-WordPostProcessItems @args }
ProcessAllObjects = { Invoke-WordProcessAllObjects @args }
})
$script:columnHeaders = @{
Name="Inputs.displayNameLabel"
Value="TableHeaders.value"
Description="TableHeaders.description"
GroupMode="SettingDetails.modeTableHeader" #assignmentTypeSelectionLabel?
Group="TableHeaders.assignedGroups"
Groups="TableHeaders.groups"
useDeviceContext="SettingDetails.installContextLabel"
uninstallOnDeviceRemoval="SettingDetails.UninstallOnRemoval"
isRemovable="SettingDetails.installAsRemovable"
vpnConfigurationId="PolicyType.vpn"
Action="SettingDetails.actionColumnName"
Schedule="ScheduledAction.List.schedule"
MessageTemplate="ScheduledAction.Notification.messageTemplate"
EmailCC="ScheduledAction.Notification.additionalRecipients"
Filter="AssignmentFilters.assignmentFilterColumnHeader"
Rule="ApplicabilityRules.GridLabel.Rule"
ValueWithLabel="TableHeaders.value"
Status="TableHeaders.status"
CombinedValueWithLabel="TableHeaders.value"
CombinedValue="TableHeaders.value"
useDeviceLicensing="TableHeaders.licenseType"
#filterMode="Filter mode" # Not in any string file yet
}
})
}
function Add-WordOptionsControl
@@ -90,6 +65,11 @@ function Add-WordOptionsControl
$global:txtWordTableHeaderStyle.Text = Get-Setting "Documentation" "WordTableHeaderStyle" ""
$global:txtWordCategoryHeaderStyle.Text = Get-Setting "Documentation" "WordCategoryHeaderStyle" ""
$global:txtWordSubCategoryHeaderStyle.Text = Get-Setting "Documentation" "WordSubCategoryHeaderStyle" ""
$global:txtWordTableTextStyle.Text = Get-Setting "Documentation" "WordTableTextStyle" ""
$global:cbWordTableCaptionPosition.ItemsSource = ("[ { Name: `"Above`",Value: `"above`" }, { Name: `"Below`",Value: `"below`" }]" | ConvertFrom-Json)
$global:cbWordTableCaptionPosition.SelectedValue = (Get-Setting "Documentation" "WordTableCaptionPosition" "below")
$global:txtWordContentControls.Text = Get-Setting "Documentation" "WordContentControls" "Year=;Address="
$global:txtWordTitleProperty.Text = Get-Setting "Documentation" "WordTitleProperty" "Intune documentation"
$global:txtWordSubjectProperty.Text = Get-Setting "Documentation" "WordSubjectProperty" "Intune documentation"
@@ -152,6 +132,9 @@ function Invoke-WordPreProcessItems
Save-Setting "Documentation" "WordTableHeaderStyle" $global:txtWordTableHeaderStyle.Text
Save-Setting "Documentation" "WordCategoryHeaderStyle" $global:txtWordCategoryHeaderStyle.Text
Save-Setting "Documentation" "WordSubCategoryHeaderStyle" $global:txtWordSubCategoryHeaderStyle.Text
Save-Setting "Documentation" "WordTableTextStyle" $global:txtWordTableTextStyle.Text
Save-Setting "Documentation" "WordTableCaptionPosition" $global:cbWordTableCaptionPosition.SelectedValue
Save-Setting "Documentation" "WordContentControls" $global:txtWordContentControls.Text
Save-Setting "Documentation" "WordTitleProperty" $global:txtWordTitleProperty.Text
Save-Setting "Documentation" "WordSubjectProperty" $global:txtWordSubjectProperty.Text
@@ -470,7 +453,7 @@ function Set-WordContentControlText
}
else
{
Write-Log "No ContentControl found with name $controlName" 2
#Write-Log "No ContentControl found with name $controlName" 2
}
}
catch
@@ -521,12 +504,12 @@ function Invoke-WordProcessItem
foreach($prop in $global:txtWordCustomProperties.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)
{
$properties += $propInfo[0]
Set-WordColumnHeaderLanguageId $propInfo[0] $propInfo[1]
Set-DocColumnHeaderLanguageId $propInfo[0] $propInfo[1]
}
else
{
@@ -574,9 +557,12 @@ function Invoke-WordProcessItem
if(($documentedObj.Assignments | measure).Count -gt 0)
{
$params = @{}
$settingProps = $null
if($documentedObj.Assignments[0].RawIntent)
{
$properties = @("GroupMode","Group","Filter","FilterMode")
$settingProps = @("Filter","FilterMode")
$settingsObj = $documentedObj.Assignments | Where { $_.Settings -ne $null } | Select -First 1
@@ -586,7 +572,7 @@ function Invoke-WordProcessItem
{
if($objProp -in $properties) { continue }
if($objProp -in @("Category","RawIntent")) { continue }
$properties += ("Settings." + $objProp)
$settingProps += ("Settings." + $objProp)
}
}
}
@@ -609,7 +595,14 @@ function Invoke-WordProcessItem
$params.Add("AddCategories", $true)
}
# Creates a standard assignments table
Add-DocTableItems $obj $objectType $documentedObj.Assignments $properties "TableHeaders.assignments" @params
if($null -ne $settingProps)
{
# Adds additional values to the assignments table for Apps assignments
Set-DocTableSettingsItems $obj $objectType $documentedObj.Assignments $settingProps 3
}
}
if($global:chkWordAttatchJsonFile.IsChecked -eq $true)
@@ -632,6 +625,44 @@ function Invoke-WordProcessItem
}
}
function Set-DocTableSettingsItems
{
param($obj, $objectType, $items, $properties, $firstColumn)
$secondColumn = $firstColumn + 1
$script:docTable.Cell(1, $firstColumn).Range.Text = (Invoke-WordTranslateColumnHeader "Settings")
$script:docTable.Cell(1, $secondColumn).Range.Text = ""
$row = 2
foreach($itemObj in $items)
{
$script:docTable.Cell($row, $firstColumn).Range.Text = ""
$script:docTable.Cell($row, $secondColumn).Range.Text = ""
$script:docTable.Cell($row, $firstColumn).Split($properties.Count,1)
$script:docTable.Cell($row, $secondColumn).Split($properties.Count,1)
$cellRow = $row
foreach($settingProp in $properties)
{
$script:docTable.Cell($cellRow, $firstColumn).Range.Text = (Invoke-WordTranslateColumnHeader ($settingProp.Split('.')[-1]))
$propArr = $settingProp.Split('.')
$tmpObj = $itemObj
$propName = $propArr[-1]
for($x = 0; $x -lt ($propArr.Count - 1);$x++)
{
$tmpObj = $tmpObj."$($propArr[$x])"
}
$script:docTable.Cell($cellRow, $secondColumn).Column.Cells($cellRow).Range.Text = "$($tmpObj.$propName)"
$cellRow++
}
$row = $row + $properties.Count
}
}
function Invoke-WordProcessAllObjects
{
param($allObjectTypeObjects)
@@ -671,54 +702,32 @@ function Invoke-WordProcessAllObjects
}
}
function Invoke-WordTranslateColumnHeader
{
param($columnName)
$lngText = ""
if($script:columnHeaders.ContainsKey($columnName))
{
$lngText = Get-LanguageString $script:columnHeaders[$columnName]
}
(?? $lngText $columnName)
}
function Invoke-WordCustomProcessItems
{
param($obj, $documentedObj)
}
function Set-WordColumnHeaderLanguageId
{
param($columnName, $lngId)
if(-not $script:columnHeaders -or -not $lngId) { return }
if($script:columnHeaders.ContainsKey($columnName))
{
$script:columnHeaders[$columnName] = $lngId
}
else
{
$script:columnHeaders.Add($columnName, $lngId)
}
}
function Add-DocTableItems
{
param($obj, $objectType, $items, $properties, $lngId, [switch]$AddCategories, [switch]$AddSubcategories, $captionOverride, [switch]$forceFullValue)
if(($items | measure).Count -eq 0)
{
return
}
$tblHeaderStyle = $global:txtWordTableHeaderStyle.Text
$tblCategoryStyle = $global:txtWordCategoryHeaderStyle.Text
$tblSubCategoryStyle = $global:txtWordSubCategoryHeaderStyle.Text
$tblTextStyle = $global:txtWordTableTextStyle.Text
$txtTableCaptionPosition = $global:cbWordTableCaptionPosition.SelectedValue
$range = $script:doc.application.selection.range
$script:docTable = $script:doc.Tables.Add($range, ($items.Count + 1), $properties.Count, [Microsoft.Office.Interop.Word.WdDefaultTableBehavior]::wdWord9TableBehavior, [Microsoft.Office.Interop.Word.WdAutoFitBehavior]::wdAutoFitWindow)
$script:docTable.ApplyStyleHeadingRows = $true
Set-DocObjectStyle $script:docTable $global:txtWordTableStyle.Text
Set-DocObjectStyle $script:docTable $global:txtWordTableStyle.Text | Out-null
if($captionOverride)
{
@@ -736,7 +745,7 @@ function Add-DocTableItems
$i = 1
foreach($prop in $properties)
{
$script:docTable.Cell(1, $i).Range.Text = (Invoke-WordTranslateColumnHeader ($prop.Split(".")[-1]))
$script:docTable.Cell(1, $i).Range.Text = (Invoke-DocTranslateColumnHeader ($prop.Split(".")[-1]))
$i++
}
@@ -816,6 +825,8 @@ function Add-DocTableItems
}
$i++
}
Set-DocObjectStyle $script:docTable.Rows($row).Range $tblTextStyle
if($itemObj.Category -and $curCategory -ne $itemObj.Category -and $AddCategories -eq $true)
{
@@ -857,13 +868,22 @@ function Add-DocTableItems
$row++
}
# -2 = Table, 1 = Below
$script:docTable.Application.Selection.InsertCaption(-2, ". $caption", $null, 1)
# -2 = Table caption, 1 = Below / 0 = Above
if($txtTableCaptionPosition -eq "above")
{
$capPos = 0
}
else
{
$capPos = 1
}
$script:docTable.Application.Selection.InsertCaption(-2, ". $caption", $null, $capPos)
Invoke-DocGoToEnd
# Add new row after the table
#$script:doc.Application.Selection.InsertParagraphAfter()
$script:doc.Application.Selection.TypeParagraph()
#$script:doc.Application.Selection.TypeParagraph()
}
function Add-DocTableScript

View File

@@ -11,7 +11,7 @@ This module is for the Endpoint Manager/Intune View. It manages Export/Import/Co
#>
function Get-ModuleVersion
{
'3.4.0'
'3.5.0'
}
function Invoke-InitializeModule
@@ -86,7 +86,7 @@ function Invoke-InitializeModule
ID="IntuneGraphAPI"
ViewPanel = $viewPanel
AuthenticationID = "MSAL"
ItemChanged = { Show-GraphObjects; Invoke-ModuleFunction "Invoke-GraphObjectsChanged"; Write-Status ""}
ItemChanged = { Show-GraphObjects -ObjectTypeChanged; Invoke-ModuleFunction "Invoke-GraphObjectsChanged"; Write-Status ""}
Deactivating = { Invoke-EMDeactivateView }
Activating = { Invoke-EMActivatingView }
Authentication = (Get-MSALAuthenticationObject)
@@ -112,6 +112,7 @@ function Invoke-InitializeModule
PostCopyCommand = { Start-PostCopyDeviceConfiguration @args }
PostGetCommand = { Start-PostGetDeviceConfiguration @args }
GroupId = "DeviceConfiguration"
NavigationProperties=$true
})
Add-ViewItem (New-Object PSObject -Property @{
@@ -124,6 +125,8 @@ function Invoke-InitializeModule
GroupId = "ConditionalAccess"
ImportExtension = { Add-ConditionalAccessImportExtensions @args }
PreImportCommand = { Start-PreImportConditionalAccess @args }
PostExportCommand = { Start-PostExportConditionalAccess @args }
ExpandAssignmentsList = $false
})
if((Get-SettingValue "PreviewFeatures" $false) -eq $true)
@@ -150,6 +153,7 @@ function Invoke-InitializeModule
Permissons=@("Policy.ReadWrite.ConditionalAccess")
ImportOrder = 50
GroupId = "ConditionalAccess"
ExpandAssignmentsList = $false
})
Add-ViewItem (New-Object PSObject -Property @{
@@ -226,6 +230,7 @@ function Invoke-InitializeModule
SkipRemoveProperties = @('Id')
GroupId = "Azure"
SkipAddIDOnExport = $true
ExpandAssignmentsList = $false
})
Add-ViewItem (New-Object PSObject -Property @{
@@ -340,6 +345,7 @@ function Invoke-InitializeModule
PostExportCommand = { Start-PostExportTermsAndConditions @args }
PreImportAssignmentsCommand = { Start-PreImportAssignmentsTermsAndConditions @args }
GroupId = "TenantAdmin"
ExpandAssignmentsList = $false
})
Add-ViewItem (New-Object PSObject -Property @{
@@ -359,6 +365,7 @@ function Invoke-InitializeModule
Permissons=@("DeviceManagementApps.ReadWrite.All")
Dependencies = @("Applications")
GroupId = "AppProtection"
ExpandAssignmentsList = $false
})
# These are also included in the managedAppPolicies API
@@ -377,6 +384,7 @@ function Invoke-InitializeModule
Dependencies = @("Applications")
Icon = "AppConfiguration"
GroupId = "AppConfiguration"
ExpandAssignmentsList = $false
})
Add-ViewItem (New-Object PSObject -Property @{
@@ -400,6 +408,7 @@ function Invoke-InitializeModule
ViewID = "IntuneGraphAPI"
PropertiesToRemove = @('uploadState','publishingState','isAssigned','dependentAppCount','supersedingAppCount','supersededAppCount','committedContentVersion','isFeatured','size','categories')
QUERYLIST = "`$filter=(microsoft.graph.managedApp/appAvailability%20eq%20null%20or%20microsoft.graph.managedApp/appAvailability%20eq%20%27lineOfBusiness%27%20or%20isAssigned%20eq%20true)&`$orderby=displayName"
QuerySearch=$true
Permissons=@("DeviceManagementApps.ReadWrite.All")
AssignmentsType="mobileAppAssignments"
AssignmentProperties = @("@odata.type","target","settings","intent")
@@ -437,10 +446,12 @@ function Invoke-InitializeModule
PreImportAssignmentsCommand = { Start-PreImportAssignmentsPolicySets @args }
PreImportCommand = { Start-PreImportPolicySets @args }
PreUpdateCommand = { Start-PreUpdatePolicySets @args }
PostListCommand = { Start-PostListPolicySets @args }
Permissons=@("DeviceManagementConfiguration.ReadWrite.All")
ImportOrder = 2000 # Policy Sets reference other objects so make sure it is imported last
Dependencies = @("Applications","AppConfiguration","AppProtection","AutoPilot","EnrollmentRestrictions","EnrollmentStatusPage","DeviceConfiguration","AdministrativeTemplates","SettingsCatalog","CompliancePolicies")
GroupId = "PolicySets"
ExpandAssignmentsList = $false # expand is not allowed, IsAssigned is set in PostListCommand
})
Add-ViewItem (New-Object PSObject -Property @{
@@ -485,6 +496,8 @@ function Invoke-InitializeModule
# Property that needs to be updated on the Compliance Policy
# deviceManagement/managementConditionStatements/$obj.conditionStatementId
# Location objects support removed from Intune
<#
Add-ViewItem (New-Object PSObject -Property @{
Title = "Locations"
Id = "Locations"
@@ -495,6 +508,7 @@ function Invoke-InitializeModule
ImportOrder = 30
GroupId = "CompliancePolicies"
})
#>
Add-ViewItem (New-Object PSObject -Property @{
Title = "Settings Catalog"
@@ -526,6 +540,8 @@ function Invoke-InitializeModule
#expand=roleassignments
PropertiesToRemoveForUpdate = @('isBuiltInRoleDefinition','isBuiltIn','roleAssignments') ### !!! ToDo: Add support for roleAssignments
GroupId = "TenantAdmin"
ExpandAssignments = $false
ExpandAssignmentsList = $false
})
Add-ViewItem (New-Object PSObject -Property @{
@@ -539,6 +555,7 @@ function Invoke-InitializeModule
ImportOrder = 10
DocumentAll = $true
GroupId = "TenantAdmin"
ExpandAssignmentsList = $false # Adds the assignmnets property but always empty
})
Add-ViewItem (New-Object PSObject -Property @{
@@ -554,6 +571,7 @@ function Invoke-InitializeModule
PostCopyCommand = { Start-PostCopyNotifications @args }
PropertiesToRemoveForUpdate = @('defaultLocale','localizedNotificationMessages') ### !!! ToDo: Add support for localizedNotificationMessages
GroupId = "CompliancePolicies"
ExpandAssignmentsList = $false
})
# This has some pre-reqs for working!
@@ -593,6 +611,7 @@ function Invoke-InitializeModule
ImportOrder = 15
GroupId = "TenantAdmin"
PropertiesToRemoveForUpdate = @('platform')
ExpandAssignmentsList = $false
})
Add-ViewItem (New-Object PSObject -Property @{
@@ -749,19 +768,34 @@ function Set-EMViewPanel
$btnRefresh.SetValue([System.Windows.Controls.Grid]::ColumnProperty,$grdTitle.ColumnDefinitions.Count - 1)
$btnRefresh.Margin = "0,0,5,3"
$btnRefresh.Cursor = "Hand"
$btnRefresh.Name = "btnRefresh"
$btnRefresh.Focusable = $false
$grdTitle.Children.Add($btnRefresh) | Out-Null
$tooltip = [System.Windows.Controls.ToolTip]::new()
$tooltip.Content = "Refresh"
$tooltip.Content = "Refresh all objects"
[System.Windows.Controls.ToolTipService]::SetToolTip($btnRefresh, $tooltip)
$panel.RegisterName($btnRefresh.Name, $btnRefresh)
$tooltip = [System.Windows.Controls.ToolTip]::new()
$tooltip.Content = "Refresh objects"
[System.Windows.Controls.ToolTipService]::SetToolTip($btnRefresh, $tooltip)
$btnRefresh.Add_Click({
# ToDo: Move this to view view object
$txtFilterText = $null
$txtFilter = $this.Parent.FindName("txtFilter")
if($txtFilter) { $txtFilter.Text = "" }
if($txtFilter) { $txtFilterText = $txtFilter.Text } #= "" }
Show-GraphObjects
Show-GraphObjects $txtFilterText
if($txtFilterText -and $txtFilter)
{
$txtFilter.Text = $txtFilterText
Invoke-FilterBoxChanged $txtFilter
}
Write-Status ""
})
}
@@ -782,11 +816,29 @@ function Set-EMViewPanel
$graphObjects | ForEach-Object { $global:dgObjects.ItemsSource.AddNewItem($_) | Out-Null }
$global:dgObjects.ItemsSource.CommitNew()
Set-GraphPagesButtonStatus
Invoke-FilterBoxChanged $global:txtFilter -ForceUpdate
Invoke-FilterBoxChanged $global:txtFilter
Write-Status ""
})
}
function Invoke-GraphObjectsChanged
{
$btnRefresh = $global:EMViewObject.ViewPanel.FindName("btnRefresh")
if($btnRefresh)
{
$tooltip = [System.Windows.Controls.ToolTipService]::GetToolTip($btnRefresh)
if($global:lstMenuItems.SelectedItem.QuerySearch -eq $true)
{
$tooltip.Content = "Refresh objects based on filter. Note: Only filtered objects will be returned. Clear filter and press refresh to reload other objects"
}
else
{
$tooltip.Content = "Refresh all objects"
}
}
}
function Invoke-EMSelectedItemsChanged
{
$hasSelectedItems = ($global:dgObjects.ItemsSource | Where IsSelected -eq $true) -or ($null -ne $global:dgObjects.SelectedItem)
@@ -2132,6 +2184,16 @@ function Update-EMPolicySetAssignment
Invoke-GraphRequest -Url $api -HttpMethod "POST" -Content $json
}
function Start-PostListPolicySets
{
param($objList, $objectType)
foreach($obj in $objList)
{
$obj | Add-Member -MemberType NoteProperty -Name "IsAssigned" -Value ($obj.Object.status -ne "notAssigned")
}
$objList
}
#endregion
#endregion Locations
@@ -2710,6 +2772,43 @@ function Start-PreImportConditionalAccess
$obj.state = $global:cbImportCAState.SelectedValue
}
}
function Start-PostExportConditionalAccess
{
param($obj, $objectType, $path)
$ids = @()
foreach($id in ($obj.conditions.users.includeGroups + $obj.conditions.users.excludeGroups))
{
if($id -in $ids) { continue }
elseif($id -eq "GuestsOrExternalUsers") { continue }
elseif($id -eq "All") { continue }
elseif($id -eq "None") { continue }
$ids += $id
Add-GraphMigrationObject $id "/groups" "Group"
}
foreach($id in ($obj.conditions.users.includeUsers +$obj.conditions.users.excludeUsers))
{
if($id -in $ids) { continue }
elseif($id -eq "GuestsOrExternalUsers") { continue }
elseif($id -eq "All") { continue }
elseif($id -eq "None") { continue }
$ids += $id
Add-GraphMigrationObject $id "/users" "User"
}
<#
$roleIds = @()
foreach($id in ($obj.conditions.users.includeRoles + $obj.conditions.users.excludeRoles))
{
if($id -in $ids) { continue }
$roleIds += $id
}
#>
}
#endregion
#region Terms of use

View File

@@ -10,7 +10,7 @@ This module is for the Endpoint Info View. It shows read-only objects in Intune
#>
function Get-ModuleVersion
{
'3.1.4'
'3.5.0'
}
function Invoke-InitializeModule
@@ -22,7 +22,7 @@ function Invoke-InitializeModule
ID = "EMInfoGraphAPI"
ViewPanel = $viewPanel
AuthenticationID = "MSAL"
ItemChanged = { Show-GraphObjects; Invoke-ModuleFunction "Invoke-GraphObjectsChanged"; Write-Status ""}
ItemChanged = { Show-GraphObjects -ObjectTypeChanged; Invoke-ModuleFunction "Invoke-GraphObjectsChanged"; Write-Status ""}
Activating = { Invoke-EMInfoActivatingView }
Authentication = (Get-MSALAuthenticationObject)
Authenticate = { Invoke-EMInfoAuthenticateToMSAL }
@@ -40,7 +40,8 @@ function Invoke-InitializeModule
API = "/deviceManagement/templates"
ShowButtons = @("Export","View")
Permissons=@("DeviceManagementConfiguration.ReadWrite.All")
Icon="EndpointSecurity"
Icon="EndpointSecurity"
ExpandAssignmentsList = $false
})
Add-ViewItem (New-Object PSObject -Property @{
@@ -50,7 +51,8 @@ function Invoke-InitializeModule
ViewProperties = @("bindStatus", "lastAppSyncDateTime", "ownerUserPrincipalName")
API = "/deviceManagement/androidManagedStoreAccountEnterpriseSettings"
ShowButtons = @("Export","View")
Permissons=@("DeviceManagementConfiguration.ReadWrite.All")
Permissons=@("DeviceManagementConfiguration.ReadWrite.All")
ExpandAssignmentsList = $false
})
Add-ViewItem (New-Object PSObject -Property @{
@@ -61,6 +63,7 @@ function Invoke-InitializeModule
ShowButtons = @("Export","View")
Permissons=@("DeviceManagementConfiguration.ReadWrite.All")
Icon = "AndroidCOWP"
ExpandAssignmentsList = $false
})
Add-ViewItem (New-Object PSObject -Property @{
@@ -70,7 +73,8 @@ function Invoke-InitializeModule
ViewProperties = @("appleId", "state", "appleId", "id")
API = "/deviceAppManagement/vppTokens"
ShowButtons = @("Export","View")
Permissons=@("DeviceManagementConfiguration.ReadWrite.All")
Permissons=@("DeviceManagementConfiguration.ReadWrite.All")
ExpandAssignmentsList = $false
})
Add-ViewItem (New-Object PSObject -Property @{
@@ -80,9 +84,9 @@ function Invoke-InitializeModule
ViewProperties = @("tokenName", "appleIdentifier", "tokenExpirationDateTime", "id")
API = "/deviceManagement/depOnboardingSettings/?`$top=100"
ShowButtons = @("Export","View")
Permissons=@("DeviceManagementServiceConfig.ReadWrite.All")
Permissons=@("DeviceManagementServiceConfig.ReadWrite.All")
ExpandAssignmentsList = $false
})
}
function Invoke-EMInfoActivatingView

File diff suppressed because it is too large Load Diff

View File

@@ -10,7 +10,7 @@ This module manages Microsoft Grap fuctions like calling APIs, managing graph ob
#>
function Get-ModuleVersion
{
'3.4.0'
'3.5.0'
}
$global:MSGraphGlobalApps = @(
@@ -61,6 +61,12 @@ function Invoke-InitializeModule
Values = @()
})
$global:appSettingSections += (New-Object PSObject -Property @{
Title = "MS Graph General"
Id = "GraphGeneral"
Values = @()
})
Add-SettingsObject (New-Object PSObject -Property @{
Title = "Root folder"
Key = "RootFolder"
@@ -132,23 +138,6 @@ function Invoke-InitializeModule
Description = "Default value for Import Scope (Tags) when importing objects"
}) "ImportExport"
Add-SettingsObject (New-Object PSObject -Property @{
Title = "Show Delete button"
Key = "EMAllowDelete"
Type = "Boolean"
DefaultValue = $false
Description = "Allow deleting individual objectes"
}) "ImportExport"
Add-SettingsObject (New-Object PSObject -Property @{
Title = "Show Bulk Delete "
Key = "EMAllowBulkDelete"
Type = "Boolean"
DefaultValue = $false
Description = "Allow using bulk delete to delete all objects of selected types"
}) "ImportExport"
Add-SettingsObject (New-Object PSObject -Property @{
Title = "Allow update on import (Preview)"
Key = "AllowUpdate"
@@ -157,7 +146,6 @@ function Invoke-InitializeModule
Description = "This will enable the option to update/replace an existing object during import"
}) "ImportExport"
Add-SettingsObject (New-Object PSObject -Property @{
Title = "Add ID to export file"
Key = "AddIDToExportFile"
@@ -171,17 +159,17 @@ function Invoke-InitializeModule
Key = "UseBatchAPI"
Type = "Boolean"
DefaultValue = $false
Description = "This will use batch API to call up to extport 20 objects on each API call"
Description = "This will use batch API to export up to 20 objects on each API call"
}) "ImportExport"
Add-SettingsObject (New-Object PSObject -Property @{
Title = "Refresh Objects after copy"
Key = "RefreshObjectsAfterCopy"
Title = "Resolve reference info"
Key = "ResolveReferenceInfo"
Type = "Boolean"
DefaultValue = $true
Description = "This will refresh all objects when after a copy. If this is disabled, the list must be refreshed manually to see the new objects. Default is true"
Description = "This will export/import info for referenced/navigation properties eg certificates in VPN profiles etc."
}) "ImportExport"
Add-SettingsObject (New-Object PSObject -Property @{
Title = "ApplicationId"
Key = "GraphAzureAppId"
@@ -202,6 +190,38 @@ function Invoke-InitializeModule
Type = "String"
Description = "Certificate for Azure App"
}) "GraphSilent"
Add-SettingsObject (New-Object PSObject -Property @{
Title = "Refresh Objects after copy"
Key = "RefreshObjectsAfterCopy"
Type = "Boolean"
DefaultValue = $true
Description = "This will refresh all objects when after a copy. If this is disabled, the list must be refreshed manually to see the new objects. Default is true"
}) "GraphGeneral"
Add-SettingsObject (New-Object PSObject -Property @{
Title = "Show Delete button"
Key = "EMAllowDelete"
Type = "Boolean"
DefaultValue = $false
Description = "Allow deleting individual objectes"
}) "GraphGeneral"
Add-SettingsObject (New-Object PSObject -Property @{
Title = "Show Bulk Delete "
Key = "EMAllowBulkDelete"
Type = "Boolean"
DefaultValue = $false
Description = "Allow using bulk delete to delete all objects of selected types"
}) "GraphGeneral"
Add-SettingsObject (New-Object PSObject -Property @{
Title = "Expand assignments"
Key = "ExpandAssignments"
Type = "Boolean"
DefaultValue = $false
Description = "Expand assignments when listing objects. This can be used in custom columns based on assignment info"
}) "GraphGeneral"
}
function Get-GraphAppInfo
@@ -210,13 +230,8 @@ function Get-GraphAppInfo
if($global:hideUI -eq $true)
{
# Set app info from custom settings
$appObj = New-Object PSObject -Property @{
ClientId = Get-SettingValue "$($PreFix)CustomAppId"
TenantId = $global:silentTenantId
RedirectUri = Get-SettingValue "$($PreFix)CustomAppRedirect"
Authority = Get-SettingValue "$($PreFix)CustomAuthority"
}
# Taken care of by authentication function
return
}
$graphAppId = Get-SettingValue $settingId
@@ -288,8 +303,8 @@ function Invoke-GraphRequest
$ODataMetadata = "full", # full, minimal, none or skip
[ValidateSet("BETA","v1.0")]
$GraphVersion = "BETA",
[ValidateSet("beta","v1.0")]
$GraphVersion = "beta",
[switch]
$AllPages,
@@ -452,7 +467,9 @@ function Get-GraphObjects
[switch]
$AllPages,
[switch]
$SingleObject)
$SingleObject,
[string]
$filter)
$params = @{}
if($objectType.ODataMetadata)
@@ -486,7 +503,7 @@ function Get-GraphObjects
if($SinglePage -eq $true)
{
#Use default page size or use below for a specific page size for testing
#$params.Add("pageSize",100)
#$params.Add("pageSize",10) #!!!
}
elseif($SingleObject -ne $true -and $SinglePage -ne $true)
{
@@ -498,14 +515,36 @@ function Get-GraphObjects
$url = $script:nextGraphPage
}
if($SingleObject -ne $true -and (Get-SettingValue "ExpandAssignments") -eq $true -and $objectType.ExpandAssignmentsList -ne $false)
{
# Expand assignments so they can be used in custom columns
if(($url.IndexOf('expand',[System.StringComparison]::InvariantCultureIgnoreCase)) -eq -1)
{
$url += (?: (($url.IndexOf('?')) -eq -1) "?" "&")
$url = "$($url)`$expand=assignments"
}
}
if($script:multipleGraphPages -eq $true -and $SingleObject -ne $true -and $filter -and $objectType.QuerySearch -eq $true)
{
# QuerySearch is only reqired when there are more pages to load
if(($url.IndexOf('search',[System.StringComparison]::InvariantCultureIgnoreCase)) -eq -1)
{
$url += (?: (($url.IndexOf('?')) -eq -1) "?" "&")
$url = "$($url)`$search=`"$($filter)`""
}
}
$graphObjects = Invoke-GraphRequest -Url $url @params
if($SinglePage -eq $true -or $AllPages -eq $true)
{
$script:nextGraphPage = $graphObjects.'@odata.nextLink'
}
if($null -eq $script:multipleGraphPages)
{
$script:multipleGraphPages = $null -ne $script:nextGraphPage
}
}
if($graphObjects -and ($graphObjects | GM -Name Value -MemberType NoteProperty))
{
$retObjects = $graphObjects.Value
@@ -515,7 +554,7 @@ function Get-GraphObjects
$retObjects = $graphObjects
}
$graphObjects = Add-GraphObectProperties $retObjects $objectType $property $exclude $SortProperty
$graphObjects = Add-GraphObjectProperties $retObjects $objectType $property $exclude $SortProperty
if($SingleObject -ne $true -and $objectType.PostListCommand)
{
@@ -525,7 +564,7 @@ function Get-GraphObjects
$graphObjects
}
function Add-GraphObectProperties
function Add-GraphObjectProperties
{
param($graphObjects,
$objectType,
@@ -548,6 +587,8 @@ function Add-GraphObectProperties
$retObjects = $graphObjects
}
$getAssignmentInfo = ((Get-SettingValue "ExpandAssignments") -eq $true -and $objectType.ExpandAssignmentsList -ne $false)
foreach($graphObject in $retObjects)
{
$params = @{}
@@ -559,7 +600,16 @@ function Add-GraphObectProperties
$objTmp | Add-Member -NotePropertyName "Object" -NotePropertyValue $graphObject
$objTmp | Add-Member -NotePropertyName "ObjectType" -NotePropertyValue $objectType
$objects += $objTmp
}
}
if($null -ne $graphObject.isAssigned)
{
$objTmp | Add-Member -NotePropertyName "IsAssigned" -NotePropertyValue $graphObject.isAssigned
}
elseif($getAssignmentInfo)
{
$objTmp | Add-Member -NotePropertyName "IsAssigned" -NotePropertyValue (($graphObject.assignments | measure).Count -gt 0)
}
}
if($objects.Count -gt 0 -and $SortProperty -and ($objects[0] | GM -MemberType NoteProperty -Name $SortProperty))
@@ -572,8 +622,15 @@ function Add-GraphObectProperties
function Show-GraphObjects
{
param($filter, [switch]$ObjectTypeChanged)
$global:curObjectType = $global:lstMenuItems.SelectedItem
if($ObjectTypeChanged -eq $true)
{
$script:multipleGraphPages = $null
}
Clear-GraphObjects
if(-not $global:MSALToken)
@@ -585,7 +642,17 @@ function Show-GraphObjects
}
elseif($global:curObjectType.'@AccessType' -eq "None")
{
$global:txtNotLoggedIn.Content = "You don't have the required permissons to access $($global:curObjectType.Title).`n`nRequired perimssons: $($global:curObjectType.Permissons)"
$requiredPermissions = ($global:curObjectType.Permissons -join ",")
$missingScopes = ?? $global:curObjectType.'@MissingScopes' $requiredPermissions
if($requiredPermissions -ne $missingScopes)
{
$requiredPermissions = "`nRequired permissions: $requiredPermissions"
}
else
{
$requiredPermissions = ""
}
$global:txtNotLoggedIn.Content = "You don't have the required permissons to access $($global:curObjectType.Title).$($requiredPermissions)`n`Missing perimssons: $missingScopes`n`nRequest consent from the 'Request Consent' link in the user login info`nor`nDisable the 'Use Default Permissions' setting to trigger consent prompt.`nNote: Changing the 'Use Default Permissions' setting will require a restart of the app`nand a 'manual' login"
$global:grdNotLoggedIn.Visibility = "Visible"
$global:grdData.Visibility = "Collapsed"
return
@@ -593,7 +660,7 @@ function Show-GraphObjects
$global:grdNotLoggedIn.Visibility = "Collapsed"
$global:grdData.Visibility = "Visible"
# Always show Import is an item is selected
# Always show Import if an item is selected
$global:btnImport.IsEnabled = $global:lstMenuItems.SelectedItem -ne $null
if(-not $global:lstMenuItems.SelectedItem) { return }
@@ -612,9 +679,9 @@ function Show-GraphObjects
$global:grdTitle.Visibility = "Visible"
}
$script:nextGraphPage = $null
$script:nextGraphPage = $null
$graphObjects = @(Get-GraphObjects -property $global:curObjectType.ViewProperties -objectType $global:curObjectType -SinglePage)
$graphObjects = @(Get-GraphObjects -property $global:curObjectType.ViewProperties -objectType $global:curObjectType -SinglePage -Filter $filter)
$dgObjects.AutoGenerateColumns = $false
$dgObjects.Columns.Clear()
@@ -857,7 +924,7 @@ function Start-GraphPreImport
}
# Remove OData properties
foreach($odataProp in ($obj.PSObject.Properties | Where { $_.Name -like "*@Odata*Link" -or $_.Name -like "*@odata.context" -or $_.Name -like "*@odata.id" -or ($_.Name -like "*@odata.type" -and $_.Name -ne "@odata.type")}))
foreach($odataProp in ($obj.PSObject.Properties | Where { $_.Name -like "*@Odata*Link" -or $_.Name -like "*@odata.context" -or $_.Name -like "*@odata.id" -or ($_.Name -like "*@odata.type" -and $_.Name -ne "@odata.type")})) # -or $_.Name -like "#CustomRef*"
{
$removeProperties += $odataProp.Name
}
@@ -890,10 +957,11 @@ function Get-GraphMetaData
{
# Graph metadata does not support Content-Length in response so size can not be used to check if it is updated
# There also no other version information in response headers. Use file date to update every week
Write-Log "Load Graph MetaData file"
$url = "https://graph.microsoft.com/beta/`$metadata"
$fileFullPath = [Environment]::ExpandEnvironmentVariables("%LOCALAPPDATA%\CloudAPIPowerShellManagement\GraphMetaData.xml")
$fi = [IO.FileInfo]$fileFullPath
$maxAge = (Get-Date).AddDays(-7)
$maxAge = (Get-Date).AddDays(-14)
if($fi.Exists -and ($fi.LastWriteTime -gt $maxAge -or $fi.CreationTime -gt $maxAge))
{
try
@@ -905,6 +973,7 @@ function Get-GraphMetaData
if(-not $global:metaDataXML)
{
Write-Log "Download Graph MetaData file"
[void][System.Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions")
$wc = New-Object System.Net.WebClient
$wc.Encoding = [System.Text.Encoding]::UTF8
@@ -1538,6 +1607,7 @@ function Show-GraphImportForm
$filesToImport = & $global:curObjectType.PreFilesImportCommand $global:curObjectType $filesToImport
}
$navigationPropObjects = @()
foreach ($fileObj in $filesToImport)
{
if($allowUpdate -and $global:cbImportType.SelectedValue -ne "alwaysImport" -and (Reset-GraphObjet $fileObj $global:dgObjects.ItemsSource))
@@ -1545,7 +1615,22 @@ function Show-GraphImportForm
continue
}
Import-GraphFile $fileObj
$importedObj = Import-GraphFile $fileObj -PassThru
if($importedObj -and $global:curObjectType.NavigationProperties -eq $true)
{
$navigationPropObjects += [PSCustomObject]@{
File = $fileObj
ImportedObject = $importedObj
}
}
}
if($navigationPropObjects)
{
foreach($navPropObj in $navigationPropObjects)
{
Set-GraphNavigationPropertiesFromFile $navPropObj
}
}
Show-GraphObjects
Show-ModalObject
@@ -1554,8 +1639,9 @@ function Show-GraphImportForm
Add-XamlEvent $script:importForm "btnGetFiles" "add_click" {
# Used when the user manually updates the path and the press Get Files
$global:dgObjectsToImport.ItemsSource = @(Get-GraphFileObjects $global:txtImportPath.Text)
if([IO.Directory]::Exists($global:txtImportPath.Text))
$path = Expand-FileName $global:txtImportPath.Text
$global:dgObjectsToImport.ItemsSource = @(Get-GraphFileObjects $path)
if([IO.Directory]::Exists($path))
{
Save-Setting "" "LastUsedFullPath" $global:txtImportPath.Text
Set-XamlProperty $script:importForm "lblMigrationTableInfo" "Content" (Get-MigrationTableInfo)
@@ -1566,7 +1652,8 @@ function Show-GraphImportForm
if($global:txtImportPath.Text)
{
$global:dgObjectsToImport.ItemsSource = @(Get-GraphFileObjects $global:txtImportPath.Text)
$path = Expand-FileName $global:txtImportPath.Text
$global:dgObjectsToImport.ItemsSource = @(Get-GraphFileObjects $path)
Set-XamlProperty $script:importForm "lblMigrationTableInfo" "Content" (Get-MigrationTableInfo)
}
@@ -1750,7 +1837,8 @@ function Start-GraphObjectImport
{
$filesToImport = & $item.ObjectType.PreFilesImportCommand $item.ObjectType $filesToImport
}
$navigationPropObjects = @()
foreach ($fileObj in @($filesToImport))
{
$objName = Get-GraphObjectName $fileObj.Object $item.ObjectType
@@ -1766,10 +1854,25 @@ function Start-GraphObjectImport
continue
}
Import-GraphFile $fileObj
$importedObj = Import-GraphFile $fileObj -PassThru
if($importedObj -and $item.ObjectType.NavigationProperties -eq $true)
{
$navigationPropObjects += [PSCustomObject]@{
File = $fileObj
ImportedObject = $importedObj
}
}
$importedObjects++
}
Save-Setting "" "LastUsedFullPath" $folder
if($navigationPropObjects)
{
foreach($navPropObj in $navigationPropObjects)
{
Set-GraphNavigationPropertiesFromFile $navPropObj
}
}
}
else
{
@@ -2010,7 +2113,7 @@ function Get-GraphFileObjects
function Import-GraphFile
{
param($file, $objectType)
param($file, $objectType, [switch]$PassThru)
if([IO.File]::Exists($file.FileInfo.FullName) -eq $false)
{
@@ -2050,7 +2153,12 @@ function Import-GraphFile
if($newObj -and $objClone.Assignments -and $global:chkImportAssignments.IsChecked -eq $true)
{
Import-GraphObjectAssignment $newObj $file.ObjectType $objClone.Assignments $file.FileInfo.FullName | Out-Null
}
}
if($PassThru -eq $true -and $newObj)
{
$newObj
}
}
catch
{
@@ -2347,7 +2455,8 @@ function Add-GraphMigrationInfo
if($objType -eq "#microsoft.graph.groupAssignmentTarget" -or
$objType -eq "#microsoft.graph.exclusionGroupAssignmentTarget")
{
Add-GroupMigrationObject $objInfo.groupid
#Add-GroupMigrationObject $objInfo.groupid
Add-GraphMigrationObject $objInfo.groupid "/groups" "Group"
}
elseif($objType -eq "#microsoft.graph.allLicensedUsersAssignmentTarget" -or
$objType -eq "#microsoft.graph.allDevicesAssignmentTarget")
@@ -2420,6 +2529,8 @@ function Add-GroupMigrationObject
if(-not $path) { return }
$path = Expand-FileName $path
# Check if group is already processed
$groupObj = Get-GraphMigrationObject $groupId
if(-not $groupObj)
@@ -2434,7 +2545,7 @@ function Add-GroupMigrationObject
if($global:AADObjectCache.ContainsKey($groupId) -eq $false) { $global:AADObjectCache.Add($groupId, $groupObj) }
# Add group to migration file
if((Add-GraphMigrationObject $groupObj $path "Group"))
if((Add-GraphMigrationObjectToFile $groupObj $path "Group"))
{
# Export group info to json file for possible import
$grouspPath = Join-Path $path "Groups"
@@ -2445,6 +2556,46 @@ function Add-GroupMigrationObject
}
}
function Add-GraphMigrationObject
{
param($objId, $grapAPI, $objTypeName)
if(-not $objId) { return }
$path = Get-GraphMigrationTableFile $global:txtExportPath.Text
if(-not $path) { return }
$path = Expand-FileName $path
# Check if object is already processed
$graphObj = Get-GraphMigrationObject $objId
if(-not $graphObj)
{
# Get object info
$graphObj = Invoke-GraphRequest "$($grapAPI)/$objId" -ODataMetadata "none"
}
if($graphObj)
{
# Add object to cache
if($global:AADObjectCache.ContainsKey($objId) -eq $false) { $global:AADObjectCache.Add($objId, $ugraphObjserObj) }
# Add object to migration file
if((Add-GraphMigrationObjectToFile $graphObj $path $objTypeName))
{
if($objTypeName -eq "Group")
{
# Export group info to json file for possible import
$grouspPath = Join-Path $path "Groups"
if(-not (Test-Path $grouspPath)) { mkdir -Path $grouspPath -Force -ErrorAction SilentlyContinue | Out-Null }
$fileName = "$grouspPath\$((Remove-InvalidFileNameChars $graphObj.displayName)).json"
ConvertTo-Json $graphObj -Depth 10 | Out-File $fileName -Force
}
}
}
}
function Get-GraphMigrationObject
{
param($objId)
@@ -2458,7 +2609,7 @@ function Get-GraphMigrationObject
}
# Adds an object to migration file if not added previously
function Add-GraphMigrationObject
function Add-GraphMigrationObjectToFile
{
param($obj, $path, $objType)
@@ -2517,6 +2668,7 @@ function Get-GraphMigrationTableForImport
$global:GraphMigrationTable = $null
# Migration table must be located in the root of the import path
$path = $global:txtImportPath.Text
$path = Expand-FileName $path
for($i = 0;$i -lt 2;$i++)
{
@@ -2659,7 +2811,7 @@ function Update-JsonForEnvironment
#region Dependency Functions
function Get-GraphDependencyDefaultObjects
{
Add-GraphDependencyObjects @("ScopeTags")
Add-GraphDependencyObjects @("ScopeTags","AssignmentFilters")
}
function Get-GraphDependencyObjects
@@ -2771,6 +2923,8 @@ function Export-GraphObjects
$global:ExportRoot = (Get-XamlProperty $script:exportForm "txtExportPath" "Text")
$folder = Get-GraphObjectFolder $objectType $global:ExportRoot (Get-XamlProperty $script:exportForm "chkAddObjectType" "IsChecked") (Get-XamlProperty $script:exportForm "chkAddCompanyName" "IsChecked")
$folder = Expand-FileName $folder
$objectsToExport = @()
if($Selected -ne $true)
@@ -2831,6 +2985,8 @@ function Export-GraphObject
Write-Log "No object to export" 3
return
}
Add-GraphNavigationProperties $obj $objectType
try
{
@@ -2871,6 +3027,177 @@ function Export-GraphObject
}
}
<#
Update the navigation references for an object
#>
function Set-GraphNavigationPropertiesFromFile
{
param($navPropObject)
if(-not $navPropObject.File -or -not $navPropObject.ImportedObject)
{
return
}
# Reload data from file. Some object properties was removed before import...
$objFileInfo = (ConvertFrom-Json (Get-Content -LiteralPath $navPropObject.File.FileInfo.FullName -Raw))
if(-not ($objFileInfo.PSObject.Properties | Where { $_.Name -like "#CustomRef_*" })) { return }
Set-GraphNavigationProperties $navPropObject.ImportedObject $objFileInfo $navPropObject.File.ObjectType
}
function Set-GraphNavigationProperties
{
param($newObj, $oldObj, $objectType, [switch]$FromOldObject)
if($objectType.NavigationProperties -ne $true) { return }
if(-not $newObj -or -not $oldObj -or -not $objectType)
{
return
}
if((Get-SettingValue "ResolveReferenceInfo") -ne $true) { return }
$entityName = $oldObj.'@odata.type'.Split('.')[-1]
$nameProp = ?? $objectType.NameProperty "displayName"
$props = Get-GraphEntityTypeProperties $entityName
foreach($prop in ($props | Where LocalName -eq "NavigationProperty" ))
{
# Is this the correct way of filter out Assignments, summaries etc.?
if($prop.ContainsTarget -eq $true) { continue }
if(-not ($oldObj."$($prop.Name)@odata.associationLink")) { continue }
$associationLink = $oldObj."$($prop.Name)@odata.associationLink" -replace $oldObj.Id,$newObj.Id
$refBodyObjs = $null #@()
$refObjName = $null
$refObjId = $null
if($FromOldObject -eq $true)
{
$navProp = Invoke-GraphRequest -URL $oldObj."$($prop.Name)@odata.navigationLink" -ODataMetadata "minimal" -NoError
if(-not $navProp) { continue }
$refObjName = Get-GraphObjectName $navProp $navProp
$refObjId = $navProp.Id
$refBodyObjs = ([PSCustomObject]@{
"@odata.id" = ("https://$global:MSALGraphEnvironment/beta/$($objectType.API)('$($navProp.Id)')")
})
}
else
{
if(-not ($oldObj."#CustomRef_$($prop.Name)")) { continue } # Not included in the export file
$idx = $oldObj."#CustomRef_$($prop.Name)".IndexOf("|:|")
if($idx -gt -1)
{
$refObjName = $oldObj."#CustomRef_$($prop.Name)".SubString(0,$idx)
}
else
{
$refObjName = $oldObj."#CustomRef_$($prop.Name)"
}
$refObjects = Invoke-GraphRequest -URL "$($objectType.API)?`$filter=$($nameProp) eq '$($refObjName)'" -NoError
$objectsFound = ($refObjects.value | measure).Count
if($objectsFound -eq 1)
{
# Are there any references that allows multiple ref objects?
foreach($refObj in $refObjects.value)
{
$refBodyObjs = ([PSCustomObject]@{
"@odata.id" = ("https://$global:MSALGraphEnvironment/beta/$($objectType.API)('$($refObj.Id)')")
})
$refObjId = $refObj.Id
}
}
elseif($objectsFound -gt 1)
{
Write-Log "Multiple objects ($objectsFound) found with $nameProp $refObjName. Skipping reference." 2
continue
}
else
{
Write-Log "No object found with $nameProp $refObjName" 2
continue
}
}
Write-Log "Add $refObjName ($refObjId) to navigation property $($prop.Name)"
$body = $refBodyObjs | ConvertTo-Json -Depth 10
Invoke-GraphRequest -URL $associationLink -HttpMethod "PUT" -Content $body | Out-Null
}
}
<#
Add Navigation Property data to the object so it included in the exported json file
#>
function Add-GraphNavigationProperties
{
param($obj, $objType)
if($objectType.NavigationProperties -ne $true) { return }
if(-not $obj.'@odata.type') { return }
if((Get-SettingValue "ResolveReferenceInfo") -ne $true) { return }
$entityName = $obj.'@odata.type'.Split('.')[-1]
$props = Get-GraphEntityTypeProperties $entityName
foreach($prop in ($props | Where LocalName -eq "NavigationProperty" ))
{
# Is this the correct way of filter out Assignments, summaries etc.?
if($prop.ContainsTarget -eq $true) { continue }
if(-not ($obj."$($prop.Name)@odata.navigationLink")) { continue }
$navProp = Invoke-GraphRequest -URL $obj."$($prop.Name)@odata.navigationLink" -ODataMetadata "minimal" -NoError
if($navProp)
{
$value = $null
$refType = ""
if($navProp.value -is [Object[]])
{
if($navProp.value.Count -gt 0 -and $navProp.value[0].'@odata.type') { $refType = $navProp.value[0].'@odata.type' }
$refValues = @()
$navProp.value | ForEach-Object { $refValues += (Get-GraphObjectName $_ $objType) }
if($refValues.Count -gt 0)
{
if(($refValues -join "") -like "*,*")
{
Write-Log "One or mor referenced objects has the comma (,) character in the name. Cannot add navigation property $($prop.Name)" 3
}
$value = ($refValues -join ",")
}
}
else
{
if($navProp.'@odata.type') { $refType = $navProp.'@odata.type' }
$value = (Get-GraphObjectName $navProp $objType)
}
if($refType -and $value)
{
$value = ($value + "|:|" + $refType)
}
$obj | Add-Member -NotePropertyName "#CustomRef_$($prop.Name)" -NotePropertyValue $value
}
}
}
function Get-GraphBatchObjects
{
param($objects, $txtNameFilter)
@@ -2932,7 +3259,7 @@ function Get-GraphBatchObjects
if($objectType -and $batchResults.Count -gt 0)
{
$batchResultsTmp = $batchResults
$batchResults = Add-GraphObectProperties $batchResultsTmp $objectType -property $objectType.ViewProperties
$batchResults = Add-GraphObjectProperties $batchResultsTmp $objectType -property $objectType.ViewProperties
$curObj = 1
foreach($obj in $batchResults)
@@ -3120,6 +3447,8 @@ function Copy-GraphObject
[System.Windows.MessageBox]::Show("No object selected`n`nSelect the $($global:curObjectType.Title) item you want to copy", "Error", "OK", "Error")
return
}
$script:copyForm = Initialize-Window ($global:AppRootFolder + "\Xaml\CopyDialog.xaml")
if(-not $script:copyForm) { return }
$newName = "$((Get-GraphObjectName $dgObjects.SelectedItem $global:curObjectType)) - Copy"
if($global:curObjectType.CopyDefaultName)
@@ -3127,10 +3456,44 @@ function Copy-GraphObject
$newName = $global:curObjectType.CopyDefaultName
$dgObjects.SelectedItem.PSObject.Properties | foreach { $newName = $newName -replace "%$($_.Name)%", $dgObjects.SelectedItem."$($_.Name)" }
}
$ret = Show-InputDialog "Copy $($global:curObjectType.Title)" "Select name for the new object" $newName
Set-XamlProperty $script:copyForm "txtObjectName" "Text" $newName
$descriptionProperty = $global:dgObjects.SelectedItem.Object | gm | Where { $_.Name -eq "Description" }
if($descriptionProperty)
{
Set-XamlProperty $script:copyForm "txtObjectDescription" "Text" $global:dgObjects.SelectedItem.Object.Description
}
else
{
Set-XamlProperty $script:copyForm "txtObjectDescription" "IsEnabled" $false
}
$script:copyForm.Add_ContentRendered({
$txtName = $script:copyForm.FindName("txtObjectName")
if($txtName)
{
$txtName.SelectAll();
}
})
Add-XamlEvent $script:copyForm "btnOk" "Add_Click" -scriptBlock ([scriptblock]{
$script:copyForm.DialogResult = $true;
})
$script:copyForm.Owner = $global:window
$script:copyForm.Icon = $global:Window.Icon
$ret = $script:copyForm.ShowDialog()
if($ret)
{
$newName = Get-XamlProperty $script:copyForm "txtObjectName" "Text"
if(-not $newName)
{
Write-Log "New name cannot be empty. Copy object skipped" 2
Write-Status ""
return
}
# Export profile
Write-Status "Export $((Get-GraphObjectName $dgObjects.SelectedItem $global:curObjectType))"
@@ -3138,7 +3501,7 @@ function Copy-GraphObject
if($global:curObjectType.PreCopyCommand)
{
if((& $global:curObjectType.PreCopyCommand $exportObj $global:curObjectType $ret))
if((& $global:curObjectType.PreCopyCommand $exportObj $global:curObjectType $newName))
{
if((Get-SettingValue "RefreshObjectsAfterCopy") -eq $true)
{
@@ -3154,15 +3517,22 @@ function Copy-GraphObject
if($obj)
{
# Import new profile
Set-GraphObjectName $obj $global:curObjectType $ret
Set-GraphObjectName $obj $global:curObjectType $newName
if((Get-XamlProperty $script:copyForm "txtObjectDescription" "IsEnabled" $false) -eq $true)
{
$obj.Description = Get-XamlProperty $script:copyForm "txtObjectDescription" "Text"
}
$newObj = Import-GraphObject $obj $global:curObjectType
if($newObj)
{
Set-GraphNavigationProperties $newObj $exportObj $global:curObjectType -FromOldObject
if($global:curObjectType.PostCopyCommand)
{
& $global:curObjectType.PostCopyCommand $exportObj $newObj $global:curObjectType
}
if((Get-SettingValue "RefreshObjectsAfterCopy") -eq $true)
{
Show-GraphObjects
@@ -3236,7 +3606,7 @@ function Show-GraphObjectInfo
$descriptionProperty = $global:dgObjects.SelectedItem.Object | gm | Where { $_.Name -eq "Description" }
if($descriptionProperty)
{
Set-XamlProperty $script:detailsForm "txtObjectDescription" "Text" $descriptionProperty.Value
Set-XamlProperty $script:detailsForm "txtObjectDescription" "Text" $global:dgObjects.SelectedItem.Object.Description
}
else
{
@@ -3612,6 +3982,11 @@ function Get-GraphEntityTypeProperties
{
param($entityType, $xml)
Get-GraphMetaData
if(-not $xml) { $xml = $global:metaDataXML }
if(-not $xml) { return }
$tmpEntity = $xml.SelectSingleNode("//*[name()='EntityType' and @Name='$entityType']")
if(-not $tmpEntity) { return }
@@ -3631,7 +4006,7 @@ function Get-GraphEntityTypeProperties
[array]::Reverse($entities)
foreach($enitiy in $entities)
{
$properties += $enitiy.SelectNodes("*[name()='Property']")
$properties += $enitiy.SelectNodes("*[name()='Property' or name()='NavigationProperty']")
}
$properties