3.3.2
This commit is contained in:
15
Core.psm1
15
Core.psm1
@@ -11,7 +11,7 @@ This module handles the WPF UI
|
||||
|
||||
function Get-ModuleVersion
|
||||
{
|
||||
'3.3.1'
|
||||
'3.3.2'
|
||||
}
|
||||
|
||||
function Start-CoreApp
|
||||
@@ -784,7 +784,7 @@ function Remove-Property
|
||||
|
||||
function Get-GridCheckboxColumn
|
||||
{
|
||||
param($bindingProperty = "IsSelected")
|
||||
param($bindingProperty = "IsSelected", [scriptblock]$scriptBlock)
|
||||
|
||||
$binding = [System.Windows.Data.Binding]::new($bindingProperty)
|
||||
$binding.UpdateSourceTrigger = [System.Windows.Data.UpdateSourceTrigger]::PropertyChanged
|
||||
@@ -792,6 +792,11 @@ function Get-GridCheckboxColumn
|
||||
$fef = [System.Windows.FrameworkElementFactory]::new([System.Windows.Controls.CheckBox])
|
||||
$binding.Mode = [System.Windows.Data.BindingMode]::TwoWay
|
||||
$fef.SetValue([System.Windows.Controls.CheckBox]::IsCheckedProperty,$binding)
|
||||
if($null -ne $scriptBlock)
|
||||
{
|
||||
[System.Windows.RoutedEventHandler]$checkedEventHandler = $scriptBlock
|
||||
$fef.AddHandler([System.Windows.Controls.CheckBox]::CheckedEvent, $checkedEventHandler)
|
||||
}
|
||||
$dt = [System.Windows.DataTemplate]::new()
|
||||
$dt.VisualTree = $fef
|
||||
$column.CellTemplate = $dt
|
||||
@@ -799,6 +804,10 @@ function Get-GridCheckboxColumn
|
||||
$header.Margin = [System.Windows.Thickness]::new(-4,0,0,0) # Align header checkbox with the row checkboxes
|
||||
$header.ToolTip = "Select/deselect all items"
|
||||
$column.Header = $header
|
||||
if($null -ne $scriptBlock)
|
||||
{
|
||||
#$header.add_click($scriptBlock)
|
||||
}
|
||||
|
||||
$column
|
||||
}
|
||||
@@ -1567,7 +1576,7 @@ function Add-DefaultSettings
|
||||
Type = "Boolean"
|
||||
DefaultValue = $false
|
||||
Description = "Enable featurs that are marked as Preview. This might require a restart and prompt for consent"
|
||||
}) "General"
|
||||
}) "General"
|
||||
}
|
||||
|
||||
function Add-SettingsObject
|
||||
|
||||
@@ -54,6 +54,8 @@ This is the first version of the documentation support.
|
||||
|
||||
* Some Endpoint Security/Settings Catalog items is not translated based on Graph API in the portal e.g. *Antivirus - Windows 10 and Windows Server (ConfigMgr)* policies. These will be documented based on Graph API information which might be different compared to the portal
|
||||
|
||||
* Markdown is currently in experimental state. The script can document to an MD file created in the Documents folder but this can be to large in environments with many objects. The script will create HTML tables to support code blocks and column span. The MD View must support HTML tables to display the document. The *Markdown Viewer* extension in Chrome was used during testing.
|
||||
|
||||
Please create an [Issue](https://github.com/Micke-K/IntuneManagement/issues) if properties are documented incorrectly or missing.
|
||||
|
||||
# Deep Dive
|
||||
|
||||
@@ -11,7 +11,7 @@ Objects can be compared based on Properties or Documentatation info.
|
||||
|
||||
function Get-ModuleVersion
|
||||
{
|
||||
'1.0.8'
|
||||
'1.0.9'
|
||||
}
|
||||
|
||||
function Invoke-InitializeModule
|
||||
@@ -127,9 +127,6 @@ function Invoke-ShowMainWindow
|
||||
$button.Margin = "0,0,5,0"
|
||||
$button.IsEnabled = $false
|
||||
$button.ToolTip = "Compare object with exported file"
|
||||
$global:dgObjects.add_selectionChanged({
|
||||
Set-XamlProperty $global:dgObjects.Parent "btnCompare" "IsEnabled" (?: ($global:dgObjects.SelectedItem -eq $null) $false $true)
|
||||
})
|
||||
|
||||
$button.Add_Click({
|
||||
Show-CompareForm $global:dgObjects.SelectedItem
|
||||
@@ -140,6 +137,12 @@ function Invoke-ShowMainWindow
|
||||
$global:spSubMenu.Children.Insert(0, $button)
|
||||
}
|
||||
|
||||
function Invoke-EMSelectedItemsChanged
|
||||
{
|
||||
$hasSelectedItems = ($global:dgObjects.ItemsSource | Where IsSelected -eq $true) -or ($null -ne $global:dgObjects.SelectedItem)
|
||||
Set-XamlProperty $global:dgObjects.Parent "btnCompare" "IsEnabled" $hasSelectedItems
|
||||
}
|
||||
|
||||
function Invoke-ViewActivated
|
||||
{
|
||||
if($global:currentViewObject.ViewInfo.ID -ne "IntuneGraphAPI") { return }
|
||||
|
||||
@@ -20,13 +20,38 @@ $global:documentationProviders = @()
|
||||
|
||||
function Get-ModuleVersion
|
||||
{
|
||||
'1.0.7'
|
||||
'1.0.8'
|
||||
}
|
||||
|
||||
function Invoke-InitializeModule
|
||||
{
|
||||
# Make sure we add the default Output types
|
||||
Add-OutputType
|
||||
|
||||
$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 Invoke-ShowMainWindow
|
||||
@@ -38,12 +63,6 @@ function Invoke-ShowMainWindow
|
||||
$button.Margin = "0,0,5,0"
|
||||
$button.IsEnabled = $false
|
||||
$button.ToolTip = "Document selected objects"
|
||||
$global:dgObjects.add_selectionChanged({
|
||||
##Set-XamlProperty $global:dgObjects.Parent "btnDocument" "IsEnabled" (?: ($global:dgObjects.SelectedItem -eq $null) $false $true)
|
||||
#$itemSelected = ($global:dgObjects.ItemsSource | Where IsSelected -eq $true).Count -ge 0 -or $global:dgObjects.SelectedItem
|
||||
|
||||
Set-XamlProperty $global:dgObjects.Parent "btnDocument" "IsEnabled" (?: ($global:dgObjects.SelectedItem -eq $null) $false $true)
|
||||
})
|
||||
|
||||
$button.Add_Click({
|
||||
|
||||
@@ -57,6 +76,12 @@ function Invoke-ShowMainWindow
|
||||
$global:spSubMenu.Children.Insert(0, $button)
|
||||
}
|
||||
|
||||
function Invoke-EMSelectedItemsChanged
|
||||
{
|
||||
$hasSelectedItems = ($global:dgObjects.ItemsSource | Where IsSelected -eq $true) -or ($null -ne $global:dgObjects.SelectedItem)
|
||||
Set-XamlProperty $global:dgObjects.Parent "btnDocument" "IsEnabled" $hasSelectedItems
|
||||
}
|
||||
|
||||
function Invoke-GraphObjectsChanged
|
||||
{
|
||||
$btnDocument = $global:spSubMenu.Children | Where-Object { $_.Name -eq "btnDocument" }
|
||||
@@ -87,6 +112,35 @@ function Invoke-ViewActivated
|
||||
}
|
||||
}
|
||||
|
||||
function Set-DocColumnHeaderLanguageId
|
||||
{
|
||||
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 Invoke-DocTranslateColumnHeader
|
||||
{
|
||||
param($columnName)
|
||||
|
||||
$lngText = ""
|
||||
if($script:columnHeaders.ContainsKey($columnName))
|
||||
{
|
||||
$lngText = Get-LanguageString $script:columnHeaders[$columnName]
|
||||
}
|
||||
|
||||
(?? $lngText $columnName)
|
||||
}
|
||||
|
||||
function Add-OutputType
|
||||
{
|
||||
param($outputInfo)
|
||||
@@ -588,27 +642,6 @@ function Add-ScopeTagStrings
|
||||
}
|
||||
}
|
||||
|
||||
function Get-AllEntityTypes
|
||||
{
|
||||
param($entityType, $xml, $hashTable)
|
||||
|
||||
if(-not $hashTable.ContainsKey($entityType))
|
||||
{
|
||||
$hashTable.Add($entityType, $xml.SelectSingleNode("//*[name()='EntityType' and @Name='$entityType']"))
|
||||
}
|
||||
|
||||
$nodes = $xml.SelectNodes("//*[@BaseType='graph.$entityType']")
|
||||
|
||||
foreach($node in $nodes)
|
||||
{
|
||||
if($node.Abstract -ne "true")
|
||||
{
|
||||
$hashTable.Add($node.Name, $node)
|
||||
}
|
||||
Get-AllEntityTypes $node.Name $xml $hashTable
|
||||
}
|
||||
}
|
||||
|
||||
function Get-ObjectPlatformFromType
|
||||
{
|
||||
param($obj)
|
||||
|
||||
482
Extensions/DocumentationMD.psm1
Normal file
482
Extensions/DocumentationMD.psm1
Normal file
@@ -0,0 +1,482 @@
|
||||
function Get-ModuleVersion
|
||||
{
|
||||
'1.0.0'
|
||||
}
|
||||
|
||||
function Invoke-InitializeModule
|
||||
{
|
||||
Add-OutputType ([PSCustomObject]@{
|
||||
Name="Markdown (Experimental)"
|
||||
Value="md"
|
||||
#OutputOptions = (Add-MDOptionsControl)
|
||||
#Activate = { Invoke-MDActivate @args }
|
||||
PreProcess = { Invoke-MDPreProcessItems @args }
|
||||
NewObjectGroup = { Invoke-MDNewObjectGroup @args }
|
||||
Process = { Invoke-MDProcessItem @args }
|
||||
PostProcess = { Invoke-MDPostProcessItems @args }
|
||||
ProcessAllObjects = { Invoke-MDProcessAllObjects @args }
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
function Invoke-MDPreProcessItems
|
||||
{
|
||||
$script:mdStrings = [System.Text.StringBuilder]::new()
|
||||
$script:sectionAnchors = @()
|
||||
$script:totAnchors = @()
|
||||
}
|
||||
|
||||
function Invoke-MDPostProcessItems
|
||||
{
|
||||
$userName = $global:me.displayName
|
||||
if($global:me.givenName -and $global:me.surname)
|
||||
{
|
||||
$userName = ($global:me.givenName + " " + $global:me.surname)
|
||||
}
|
||||
|
||||
$script:mdContent = [System.Text.StringBuilder]::new()
|
||||
|
||||
$script:mdContent.AppendLine("# $((?? $global:txtMDTitleProperty.Text "Intune documentation"))")
|
||||
$script:mdContent.AppendLine("")
|
||||
$script:mdContent.AppendLine("")
|
||||
|
||||
$mail = ""
|
||||
if($global:me.mail)
|
||||
{
|
||||
$mail = " ($($global:me.mail))"
|
||||
}
|
||||
|
||||
$script:mdContent.AppendLine("*Organization:* $($global:Organization.displayName)`n")
|
||||
$script:mdContent.AppendLine("*Generated by:* $userName$mail`n")
|
||||
$script:mdContent.AppendLine("*Generated:* $((Get-Date).ToShortDateString()) $((Get-Date).ToLongTimeString())`n")
|
||||
|
||||
if($script:sectionAnchors.Count -gt 0)
|
||||
{
|
||||
$script:mdContent.AppendLine("")
|
||||
$script:mdContent.AppendLine("## Table of Contents")
|
||||
}
|
||||
|
||||
foreach($header in $script:sectionAnchors)
|
||||
{
|
||||
$script:mdContent.AppendLine("[$($header.Name)](#$($header.Anchor))`n")
|
||||
}
|
||||
|
||||
$script:mdContent.AppendLine("")
|
||||
$mdText = $script:mdContent.ToString()
|
||||
$mdText += $script:mdStrings.ToString()
|
||||
|
||||
$fileName = Expand-FileName "%MyDocuments%\%Organization%-%Date%.md"
|
||||
|
||||
try
|
||||
{
|
||||
$mdText | Out-File -FilePath $fileName -Force -Encoding utf8 -ErrorAction Stop
|
||||
Write-Log "Markdown document $fileName saved successfully"
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-LogError "Failed to save Markdown file" $_.Exception
|
||||
}
|
||||
}
|
||||
|
||||
function Invoke-MDNewObjectGroup
|
||||
{
|
||||
param($obj, $documentedObj)
|
||||
|
||||
$objectTypeString = Get-ObjectTypeString $obj.Object $obj.ObjectType
|
||||
|
||||
Add-MDHeader "$((?? $objectTypeString $obj.ObjectType.Title))" -Level 1 -USEHtml
|
||||
|
||||
}
|
||||
|
||||
function Invoke-MDProcessItem
|
||||
{
|
||||
param($obj, $objectType, $documentedObj)
|
||||
|
||||
if(!$documentedObj -or !$obj -or !$objectType) { return }
|
||||
|
||||
$objName = Get-GraphObjectName $obj $objectType
|
||||
|
||||
Add-MDHeader $objName -Level 2 -USEHtml
|
||||
|
||||
$script:mdStrings.AppendLine("")
|
||||
|
||||
try
|
||||
{
|
||||
foreach($tableType in @("BasicInfo","FilteredSettings"))
|
||||
{
|
||||
if($tableType -eq "BasicInfo")
|
||||
{
|
||||
$properties = @("Name","Value")
|
||||
}
|
||||
elseif($global:cbMDDocumentationProperties.SelectedValue -eq 'extended' -and $documentedObj.DisplayProperties)
|
||||
{
|
||||
$properties = @("Name","Value","Description")
|
||||
}
|
||||
elseif($global:cbMDDocumentationProperties.SelectedValue -eq 'custom' -and $global:txtMDCustomProperties.Text)
|
||||
{
|
||||
$properties = @()
|
||||
|
||||
foreach($prop in $global:txtMDCustomProperties.Text.Split(","))
|
||||
{
|
||||
# This will add language support for custom columens (or replacing existing header)
|
||||
$propInfo = $prop.Split('=')
|
||||
if(($propInfo | measure).Count -gt 1)
|
||||
{
|
||||
$properties += $propInfo[0]
|
||||
Set-DocColumnHeaderLanguageId $propInfo[0] $propInfo[1]
|
||||
}
|
||||
else
|
||||
{
|
||||
$properties += $prop
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$properties = (?? $documentedObj.DefaultDocumentationProperties (@("Name","Value")))
|
||||
}
|
||||
|
||||
$lngId = ?: ($tableType -eq "BasicInfo") "SettingDetails.basics" "TableHeaders.settings" -AddCategories
|
||||
|
||||
Add-MDTableItems $obj $objectType ($documentedObj.$tableType) $properties $lngId -AddCategories -AddSubcategories
|
||||
|
||||
#Add-MDTableItems $obj $objectType ($documentedObj.$tableType) $properties $lngId `
|
||||
# -AddCategories:($global:chkMDAddCategories.IsChecked -eq $true) `
|
||||
# -AddSubcategories:($global:chkMDAddSubCategories.IsChecked -eq $true)
|
||||
}
|
||||
|
||||
if(($documentedObj.ComplianceActions | measure).Count -gt 0)
|
||||
{
|
||||
$properties = @("Action","Schedule","MessageTemplate","EmailCC")
|
||||
|
||||
Add-MDTableItems $obj $objectType $documentedObj.ComplianceActions $properties "Category.complianceActionsLabel"
|
||||
}
|
||||
|
||||
if(($documentedObj.ApplicabilityRules | measure).Count -gt 0)
|
||||
{
|
||||
$properties = @("Rule","Property","Value")
|
||||
|
||||
Add-MDTableItems $obj $objectType $documentedObj.ApplicabilityRules $properties "SettingDetails.applicabilityRules"
|
||||
}
|
||||
|
||||
Add-MDObjectSettings $obj $objectType $documentedObj
|
||||
|
||||
if(($documentedObj.Assignments | measure).Count -gt 0)
|
||||
{
|
||||
$params = @{}
|
||||
if($documentedObj.Assignments[0].RawIntent)
|
||||
{
|
||||
$properties = @("GroupMode","Group","Filter","FilterMode")
|
||||
|
||||
$settingsObj = $documentedObj.Assignments | Where { $_.Settings -ne $null } | Select -First 1
|
||||
|
||||
if($settingsObj)
|
||||
{
|
||||
foreach($objProp in $settingsObj.Settings.Keys)
|
||||
{
|
||||
if($objProp -in $properties) { continue }
|
||||
if($objProp -in @("Category","RawIntent")) { continue }
|
||||
$properties += ("Settings." + $objProp)
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$isFilterAssignment = $false
|
||||
foreach($assignment in $documentedObj.Assignments)
|
||||
{
|
||||
if(($assignment.target.PSObject.Properties | Where Name -eq "deviceAndAppManagementAssignmentFilterType"))
|
||||
{
|
||||
$isFilterAssignment = $true
|
||||
break
|
||||
}
|
||||
}
|
||||
$properties = @("Group")
|
||||
if($isFilterAssignment)
|
||||
{
|
||||
$properties += @("Filter","FilterMode")
|
||||
}
|
||||
$params.Add("AddCategories", $true)
|
||||
}
|
||||
|
||||
Add-MDTableItems $obj $objectType $documentedObj.Assignments $properties "TableHeaders.assignments" @params
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-LogError "Failed to process object $objName" $_.Exception
|
||||
}
|
||||
}
|
||||
|
||||
function Add-MDTableItems
|
||||
{
|
||||
param($obj, $objectType, $items, $properties, $lngId, [switch]$AddCategories, [switch]$AddSubcategories, $captionOverride)
|
||||
|
||||
if($captionOverride)
|
||||
{
|
||||
$caption = $captionOverride
|
||||
}
|
||||
elseif($lngId)
|
||||
{
|
||||
$caption = "$((Get-LanguageString $lngId)) - $((Get-GraphObjectName $obj $objectType))"
|
||||
}
|
||||
else
|
||||
{
|
||||
$caption = "$((Get-GraphObjectName $obj $objectType)) ($($objectType.Title))"
|
||||
}
|
||||
|
||||
$tableText = [System.Text.StringBuilder]::new()
|
||||
$tableText.AppendLine("<table>")
|
||||
$tableText.AppendLine("<tr>")
|
||||
$columnHeaders = "|"
|
||||
$columnChars = "|"
|
||||
$columnCount = 0
|
||||
foreach($prop in $properties)
|
||||
{
|
||||
$tableText.AppendLine("<td> $($prop.Split(".")[-1]) </td>")
|
||||
$columnCount++
|
||||
|
||||
$columnHeaders += ((Invoke-DocTranslateColumnHeader ($prop.Split(".")[-1])) + "|")
|
||||
$columnChars += "----|"
|
||||
}
|
||||
$tableText.AppendLine("</tr>")
|
||||
|
||||
#Add-MDText $columnHeaders
|
||||
#Add-MDText $columnChars
|
||||
|
||||
$curCategory = ""
|
||||
$curSubCategory = ""
|
||||
|
||||
$columnCategory = $null
|
||||
$columnSubCategory = $null
|
||||
|
||||
foreach($itemObj in $items)
|
||||
{
|
||||
if($itemObj.Category -and $curCategory -ne $itemObj.Category -and $AddCategories -eq $true)
|
||||
{
|
||||
$tableText.AppendLine("<tr>")
|
||||
$tableText.AppendLine("<td colspan=`"$($columnCount)`">`n`n**$((Set-MDText $itemObj.Category))**`n`n</td>")
|
||||
$tableText.AppendLine("</tr>")
|
||||
|
||||
#$columnCategory = "|**" + (Set-MDText $itemObj.Category) + "**|"
|
||||
#Add-MDText $columnCategory
|
||||
$curCategory = $itemObj.Category
|
||||
$curSubCategory = ""
|
||||
}
|
||||
|
||||
if($itemObj.SubCategory -and $curSubCategory -ne $itemObj.SubCategory -and $AddSubcategories -eq $true)
|
||||
{
|
||||
$tableText.AppendLine("<tr>")
|
||||
$tableText.AppendLine("<td colspan=`"$($columnCount)`">`n`n***$((Set-MDText $itemObj.SubCategory))***`n`n</td>")
|
||||
$tableText.AppendLine("</tr>")
|
||||
|
||||
#$columnSubCategory = "|***" + (Set-MDText $itemObj.SubCategory) + "***|"
|
||||
#Add-MDText $columnSubCategory
|
||||
$curSubCategory = $itemObj.SubCategory
|
||||
}
|
||||
|
||||
#$columnData = "|"
|
||||
try
|
||||
{
|
||||
$tableText.AppendLine("<tr>")
|
||||
|
||||
foreach($prop in $properties)
|
||||
{
|
||||
try
|
||||
{
|
||||
# This adds support for properties like Settings.PropName
|
||||
$propArr = $prop.Split('.')
|
||||
$tmpObj = $itemObj
|
||||
$propName = $propArr[-1]
|
||||
for($x = 0; $x -lt ($propArr.Count - 1);$x++)
|
||||
{
|
||||
$tmpObj = $tmpObj."$($propArr[$x])"
|
||||
}
|
||||
$tableText.AppendLine("<td>$((Set-MDText "$($tmpObj.$propName)" -CodeBlock))</td>")
|
||||
#$columnData += "$((Set-MDText "$($tmpObj.$propName)"))|"
|
||||
}
|
||||
catch
|
||||
{
|
||||
#$columnData += "|"
|
||||
Write-LogError "Failed to add property value for $prop" $_.Exception
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Log "Failed to process property" 2
|
||||
}
|
||||
finally
|
||||
{
|
||||
$tableText.AppendLine("</tr>")
|
||||
}
|
||||
|
||||
#Add-MDText $columnData
|
||||
}
|
||||
|
||||
$tableText.AppendLine("</table>")
|
||||
Add-MDText $tableText.ToString()
|
||||
|
||||
Add-MDHeader $caption -Level 6 -TOT -AddParagraph
|
||||
}
|
||||
|
||||
function Add-MDText
|
||||
{
|
||||
param($text, [switch]$AddParagraph)
|
||||
|
||||
$script:mdStrings.AppendLine($text)
|
||||
|
||||
if($AddParagraph -eq $true)
|
||||
{
|
||||
# Add new paragraph by default
|
||||
$script:mdStrings.AppendLine("")
|
||||
}
|
||||
}
|
||||
|
||||
function Set-MDText
|
||||
{
|
||||
param($text, [switch]$CodeBlock)
|
||||
|
||||
if($CodeBlock -eq $true)
|
||||
{
|
||||
$trimText = $text.Trim()
|
||||
if($trimText.StartsWith("<") -and $trimText.EndsWith(">"))
|
||||
{
|
||||
return ([Environment]::NewLine + [Environment]::NewLine + "``````xml" + [Environment]::NewLine + $text + [Environment]::NewLine + "``````" + [Environment]::NewLine + [Environment]::NewLine)
|
||||
}
|
||||
}
|
||||
|
||||
$text = $text.Replace("|", '`|')
|
||||
$text = $text.Replace("*", '`*')
|
||||
$text = $text.Replace("$", '`$')
|
||||
$text = $text.Replace("`r`n", "<br />")
|
||||
$text = $text.Replace("`n", "<br />")
|
||||
|
||||
$text
|
||||
}
|
||||
|
||||
function Add-MDHeader
|
||||
{
|
||||
param($text, [int]$level = 1, [switch]$AddParagraph, [switch]$UseHTML, [switch]$ToT, [switch]$SkipTOC)
|
||||
|
||||
$prefix = ""
|
||||
if($ToT -eq $true)
|
||||
{
|
||||
$prefix = "Table $(($script:totAnchors.Count + 1)). "
|
||||
}
|
||||
|
||||
if($UseHTML -eq $true)
|
||||
{
|
||||
if($ToT -eq $true)
|
||||
{
|
||||
$sectionAnchor = "table-$(($script:totAnchors.Count + 1))"
|
||||
}
|
||||
else
|
||||
{
|
||||
$sectionAnchor = "section-$(($script:sectionAnchors.Count + 1))"
|
||||
}
|
||||
|
||||
$script:mdStrings.AppendLine("<h$level id=`"$prefix$($sectionAnchor)`">$text</h$level>")
|
||||
}
|
||||
else
|
||||
{
|
||||
# Warnig: Not complete! Use HTML if not working...
|
||||
$text = "$prefix$text"
|
||||
$sectionAnchor = $text.ToLower().Replace(" ","-").Replace("[","").Replace("]","")
|
||||
|
||||
$mdHeader = [String]::new('#',$level)
|
||||
$script:mdStrings.AppendLine("$mdHeader $text")
|
||||
}
|
||||
|
||||
if($ToT -eq $true)
|
||||
{
|
||||
$script:totAnchors += [PSCustomObject]@{
|
||||
Name = $text
|
||||
Anchor = $sectionAnchor
|
||||
}
|
||||
}
|
||||
elseif($SkipTOC -ne $true)
|
||||
{
|
||||
$script:sectionAnchors += [PSCustomObject]@{
|
||||
Name = $text
|
||||
Anchor = $sectionAnchor
|
||||
}
|
||||
}
|
||||
|
||||
if($AddParagraph -eq $true)
|
||||
{
|
||||
# Add new paragraph by default
|
||||
$script:mdStrings.AppendLine("`n")
|
||||
}
|
||||
}
|
||||
|
||||
function Add-MDObjectSettings
|
||||
{
|
||||
param($obj, $objectType, $documentedObj)
|
||||
|
||||
if($obj."@OData.Type" -eq "#microsoft.graph.deviceManagementScript")
|
||||
{
|
||||
if($obj.ScriptContent)
|
||||
{
|
||||
$script:mdStrings.AppendLine("~~~powershell")
|
||||
$script:mdStrings.AppendLine((Get-DocScriptContent $obj.ScriptContent))
|
||||
$script:mdStrings.AppendLine("~~~")
|
||||
$caption = "{1} - {0}" -f $obj.fileName,(Get-LanguageString "WindowsManagement.powerShellScriptObjectName")
|
||||
Add-MDHeader $caption -Level 6 -SkipTOC -AddParagraph
|
||||
}
|
||||
}
|
||||
if($obj."@OData.Type" -eq "#microsoft.graph.deviceShellScript")
|
||||
{
|
||||
if($obj.ScriptContent)
|
||||
{
|
||||
$script:mdStrings.AppendLine("~~~shell")
|
||||
$script:mdStrings.AppendLine((Get-DocScriptContent $obj.ScriptContent))
|
||||
$script:mdStrings.AppendLine("~~~")
|
||||
|
||||
$caption = "{1} - {0}" -f $obj.fileName,(Get-LanguageString "WindowsManagement.shellScriptObjectName")
|
||||
Add-MDHeader $caption -Level 6 -SkipTOC -AddParagraph
|
||||
}
|
||||
}
|
||||
elseif($obj."@OData.Type" -eq "#microsoft.graph.deviceHealthScript")
|
||||
{
|
||||
if($obj.detectionScriptContent)
|
||||
{
|
||||
$script:mdStrings.AppendLine("~~~powershell")
|
||||
$script:mdStrings.AppendLine((Get-DocScriptContent $obj.detectionScriptContent))
|
||||
$script:mdStrings.AppendLine("~~~")
|
||||
$caption = Get-LanguageString "ProactiveRemediations.Create.Settings.DetectionScriptMultiLineTextBox.label"
|
||||
Add-MDHeader $caption -Level 6 -SkipTOC -AddParagraph
|
||||
}
|
||||
|
||||
if($obj.remediationScriptContent)
|
||||
{
|
||||
$script:mdStrings.AppendLine("~~~powershell")
|
||||
$script:mdStrings.AppendLine((Get-DocScriptContent $obj.remediationScriptContent))
|
||||
$script:mdStrings.AppendLine("~~~")
|
||||
$caption = Get-LanguageString "ProactiveRemediations.Create.Settings.RemediationScriptMultiLineTextBox.label"
|
||||
Add-MDHeader $caption -Level 6 -SkipTOC -AddParagraph
|
||||
}
|
||||
}
|
||||
elseif($obj."@OData.Type" -eq "#microsoft.graph.win32LobApp")
|
||||
{
|
||||
foreach($rule in ($obj.requirementRules | Where { $_.'@OData.Type' -eq "#microsoft.graph.win32LobAppPowerShellScriptRequirement" } ))
|
||||
{
|
||||
$script:mdStrings.AppendLine("~~~powershell")
|
||||
$script:mdStrings.AppendLine((Get-DocScriptContent $obj.scriptContent))
|
||||
$script:mdStrings.AppendLine("~~~")
|
||||
$caption = "{0} - {1}" -f @($obj.displayName, "Requirement script")
|
||||
Add-MDHeader $caption -Level 6 -SkipTOC -AddParagraph
|
||||
}
|
||||
|
||||
foreach($rule in ($obj.detectionRules | Where { $_.'@OData.Type' -eq "#microsoft.graph.win32LobAppPowerShellScriptDetection" } ))
|
||||
{
|
||||
$script:mdStrings.AppendLine("~~~powershell")
|
||||
$script:mdStrings.AppendLine((Get-DocScriptContent $obj.scriptContent))
|
||||
$script:mdStrings.AppendLine("~~~")
|
||||
$caption = "{0} - {1}" -f @($obj.displayName,(Get-LanguageString "ProactiveRemediations.Create.Settings.DetectionScriptMultiLineTextBox.label"))
|
||||
Add-MDHeader $caption -Level 6 -SkipTOC -AddParagraph
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
#https://docs.microsoft.com/en-us/office/vba/api/overview/word
|
||||
function Get-ModuleVersion
|
||||
{
|
||||
'1.0.6'
|
||||
'1.0.7'
|
||||
}
|
||||
|
||||
function Invoke-InitializeModule
|
||||
@@ -163,7 +163,7 @@ function Invoke-WordPreProcessItems
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-LogError "Failed to create document based on tmeplate: $($global:txtWordDocumentTemplate.Text)" $_.Exception
|
||||
Write-LogError "Failed to create document based on template: $($global:txtWordDocumentTemplate.Text)" $_.Exception
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -442,7 +442,7 @@ function Invoke-WordProcessItem
|
||||
|
||||
foreach($prop in $global:txtWordCustomProperties.Text.Split(","))
|
||||
{
|
||||
# This will add language support for custom colument (or replacing existing header)
|
||||
# This will add language support for custom columens (or replacing existing header)
|
||||
$propInfo = $prop.Split('=')
|
||||
if(($propInfo | measure).Count -gt 1)
|
||||
{
|
||||
|
||||
@@ -11,7 +11,7 @@ This module is for the Endpoint Manager/Intune View. It manages Export/Import/Co
|
||||
#>
|
||||
function Get-ModuleVersion
|
||||
{
|
||||
'3.1.13'
|
||||
'3.1.14'
|
||||
}
|
||||
|
||||
function Invoke-InitializeModule
|
||||
@@ -225,6 +225,7 @@ function Invoke-InitializeModule
|
||||
Icon = "Branding"
|
||||
SkipRemoveProperties = @('Id')
|
||||
GroupId = "Azure"
|
||||
SkipAddIDOnExport = $true
|
||||
})
|
||||
|
||||
Add-ViewItem (New-Object PSObject -Property @{
|
||||
@@ -722,9 +723,7 @@ function Set-EMViewPanel
|
||||
Set-XamlProperty $panel "btnDelete" "Visibility" (?: ($allowDelete -eq $true) "Visible" "Collapsed")
|
||||
|
||||
$global:dgObjects.add_selectionChanged({
|
||||
Set-XamlProperty $this.Parent "btnView" "IsEnabled" (?: ($null -eq $global:dgObjects.SelectedItem) $false $true)
|
||||
Set-XamlProperty $this.Parent "btnCopy" "IsEnabled" (?: ($null -eq $global:dgObjects.SelectedItem) $false $true)
|
||||
Set-XamlProperty $this.Parent "btnDelete" "IsEnabled" (?: ($null -eq $global:dgObjects.SelectedItem -and $global:curObjectType.AllowDelete -ne $false) $false $true)
|
||||
Invoke-ModuleFunction "Invoke-EMSelectedItemsChanged"
|
||||
})
|
||||
|
||||
# ToDo: Move this to the view object
|
||||
@@ -760,12 +759,40 @@ function Set-EMViewPanel
|
||||
Show-GraphObjects
|
||||
Write-Status ""
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
$global:btnLoadAllPages.add_click({
|
||||
Write-Status "Loading $($global:curObjectType.Title) objects"
|
||||
$graphObjects = @(Get-GraphObjects -property $global:curObjectType.ViewProperties -objectType $global:curObjectType -AllPages)
|
||||
$graphObjects | ForEach-Object { $global:dgObjects.ItemsSource.AddNewItem($_) | Out-Null }
|
||||
$global:dgObjects.ItemsSource.CommitNew()
|
||||
Set-GraphPagesButtonStatus
|
||||
Invoke-FilterBoxChanged $global:txtFilter -ForceUpdate
|
||||
Write-Status ""
|
||||
})
|
||||
|
||||
$global:btnLoadNextPage.add_click({
|
||||
Write-Status "Loading $($global:curObjectType.Title) objects"
|
||||
$graphObjects = @(Get-GraphObjects -property $global:curObjectType.ViewProperties -objectType $global:curObjectType -SinglePage)
|
||||
$graphObjects | ForEach-Object { $global:dgObjects.ItemsSource.AddNewItem($_) | Out-Null }
|
||||
$global:dgObjects.ItemsSource.CommitNew()
|
||||
Set-GraphPagesButtonStatus
|
||||
Invoke-FilterBoxChanged $global:txtFilter -ForceUpdate
|
||||
Write-Status ""
|
||||
})
|
||||
}
|
||||
|
||||
function Invoke-EMSelectedItemsChanged
|
||||
{
|
||||
$hasSelectedItems = ($global:dgObjects.ItemsSource | Where IsSelected -eq $true) -or ($null -ne $global:dgObjects.SelectedItem)
|
||||
Set-XamlProperty $global:dgObjects.Parent "btnView" "IsEnabled" $hasSelectedItems #(?: ($null -eq ($global:dgObjects.SelectedItem)) $false $true)
|
||||
Set-XamlProperty $global:dgObjects.Parent "btnCopy" "IsEnabled" $hasSelectedItems #(?: ($null -eq $global:dgObjects.SelectedItem) $false $true)
|
||||
Set-XamlProperty $global:dgObjects.Parent "btnDelete" "IsEnabled" $hasSelectedItems #(?: ($null -eq $global:dgObjects.SelectedItem -and $global:curObjectType.AllowDelete -ne $false) $false $true)
|
||||
}
|
||||
|
||||
function Invoke-FilterBoxChanged
|
||||
{
|
||||
param($txtBox)
|
||||
param($txtBox,[switch]$ForceUpdate)
|
||||
|
||||
$filter = $null
|
||||
|
||||
@@ -774,11 +801,18 @@ function Invoke-FilterBoxChanged
|
||||
$txtBox.FontStyle = "Italic"
|
||||
$txtBox.Tag = 1
|
||||
$txtBox.Text = "Filter"
|
||||
$txtBox.Foreground="Lightgray"
|
||||
$txtBox.Foreground="Lightgray"
|
||||
}
|
||||
elseif($ForceUpdate -eq $true)
|
||||
{
|
||||
$dgObjects.ItemsSource.Filter = $dgObjects.ItemsSource.Filter
|
||||
}
|
||||
elseif($txtBox.Tag -eq "1" -and $txtBox.Text -eq "Filter" -and $txtBox.IsFocused -eq $false)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if($txtBox.Tag -eq "1" -and $txtBox.Text -eq "Filter" -and $txtBox.IsFocused -eq $false) { return }
|
||||
{
|
||||
$txtBox.FontStyle = "Normal"
|
||||
$txtBox.Tag = $null
|
||||
$txtBox.Foreground="Black"
|
||||
@@ -800,11 +834,9 @@ function Invoke-FilterBoxChanged
|
||||
}
|
||||
}
|
||||
|
||||
if($dgObjects.ItemsSource -is [System.Windows.Data.ListCollectionView])
|
||||
if($dgObjects.ItemsSource -is [System.Windows.Data.ListCollectionView] -and $txtBox.IsFocused -eq $true)
|
||||
{
|
||||
# This causes odd behaviour with focus e.g. and item has to be clicked twice to be selected
|
||||
$dgObjects.ItemsSource.Filter = $filter
|
||||
$dgObjects.ItemsSource.Refresh()
|
||||
}
|
||||
|
||||
$allObjectsCount = 0
|
||||
@@ -869,9 +901,15 @@ function Start-PostExportEndpointSecurity
|
||||
{
|
||||
param($obj, $objectType, $path)
|
||||
|
||||
$fileName = (Get-GraphObjectName $obj $objectType)
|
||||
if((Get-SettingValue "AddIDToExportFile") -eq $true -and $obj.Id)
|
||||
{
|
||||
$fileName = ($fileName + "_" + $obj.Id)
|
||||
}
|
||||
|
||||
$settings = Invoke-GraphRequest -Url "$($objectType.API)/$($obj.id)/settings"
|
||||
$settingsJson = "{ `"settings`": $((ConvertTo-Json $settings.value -Depth 20 ))`n}"
|
||||
$fileName = "$path\$((Remove-InvalidFileNameChars (Get-GraphObjectName $obj $objectType)))_Settings.json"
|
||||
$fileName = "$path\$((Remove-InvalidFileNameChars $fileName))_Settings.json"
|
||||
$settingsJson | Out-File -LiteralPath $fileName -Force
|
||||
}
|
||||
|
||||
@@ -1142,8 +1180,8 @@ function Start-PostGetIntuneBranding
|
||||
|
||||
foreach($imgType in @("themeColorLogo","lightBackgroundLogo","landingPageCustomizedImage"))
|
||||
{
|
||||
Write-LogDebug "Get $imgType for $($obj.profileName)"
|
||||
$imgJson = Invoke-GraphRequest -Url "$($objectType.API)/$($obj.Id)/$imgType"
|
||||
Write-LogDebug "Get $imgType for $($obj.Object.profileName)"
|
||||
$imgJson = Invoke-GraphRequest -Url "$($objectType.API)/$($obj.Object.Id)/$imgType"
|
||||
if($imgJson.Value)
|
||||
{
|
||||
$obj.Object.$imgType = $imgJson
|
||||
@@ -1793,9 +1831,23 @@ function Start-PostExportAdministrativeTemplate
|
||||
{
|
||||
param($obj, $objectType, $path)
|
||||
|
||||
$fileName = (Get-GraphObjectName $obj $objectType)
|
||||
if((Get-SettingValue "AddIDToExportFile") -eq $true -and $obj.Id)
|
||||
{
|
||||
$fileName = ($fileName + "_" + $obj.Id)
|
||||
}
|
||||
|
||||
# Collect and save all the settings of the Administrative Templates profile
|
||||
$settings = Get-GPOObjectSettings $obj
|
||||
$fileName = "$path\$((Remove-InvalidFileNameChars (Get-GraphObjectName $obj $objectType)))_Settings.json"
|
||||
if($obj.definitionValues)
|
||||
{
|
||||
$settings = $obj.definitionValues
|
||||
}
|
||||
else
|
||||
{
|
||||
$settings = Get-GPOObjectSettings $obj
|
||||
}
|
||||
|
||||
$fileName = "$path\$((Remove-InvalidFileNameChars $fileName))_Settings.json"
|
||||
ConvertTo-Json $settings -Depth 20 | Out-File -LiteralPath $fileName -Force
|
||||
}
|
||||
|
||||
@@ -1858,7 +1910,7 @@ function Start-PostGetAdministrativeTemplate
|
||||
$obj.Object | Add-Member Noteproperty -Name "definitionValues" -Value $definitionValues -Force
|
||||
}
|
||||
<#
|
||||
# Leave for now. This only loads the configured defenition values and not the values specified.
|
||||
# Leave for now. This only loads the configured definition values and not the values specified.
|
||||
# That would require enumerating each definition value which takes time.
|
||||
$definitionValues = (Invoke-GraphRequest "deviceManagement/groupPolicyConfigurations('$($obj.Id)')/definitionValues?`$expand=definition(`$select=id,classType,displayName,policyType,groupPolicyCategoryId)" -ODataMetadata "minimal").value
|
||||
|
||||
@@ -2025,8 +2077,21 @@ function Start-PostExportRoleDefinitions
|
||||
{
|
||||
param($obj, $objectType, $path)
|
||||
|
||||
$fileName = "$path\$((Remove-InvalidFileNameChars (Get-GraphObjectName $obj $objectType))).json"
|
||||
$tmpObj = Get-Content -LiteralPath $fileName | ConvertFrom-Json
|
||||
$fileName = (Get-GraphObjectName $obj $objectType)
|
||||
if((Get-SettingValue "AddIDToExportFile") -eq $true -and $obj.Id)
|
||||
{
|
||||
$fileName = ($fileName + "_" + $obj.Id)
|
||||
}
|
||||
$tmpObj = $null
|
||||
$fileName = "$path\$((Remove-InvalidFileNameChars $fileName)).json"
|
||||
if([IO.File]::Exists($fileName))
|
||||
{
|
||||
$tmpObj = Get-Content -LiteralPath $fileName | ConvertFrom-Json
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Log "File not found: $fileName. Could not get role assignments" 3
|
||||
}
|
||||
|
||||
if(($tmpObj.RoleAssignments | measure).Count -gt 0)
|
||||
{
|
||||
@@ -2397,10 +2462,15 @@ function Add-EMAssignmentsToExportFile
|
||||
{
|
||||
param($obj, $objectType, $path, $Url = "")
|
||||
|
||||
$fileName = "$path\$((Remove-InvalidFileNameChars (Get-GraphObjectName $obj $objectType))).json"
|
||||
$fileName = (Get-GraphObjectName $obj $objectType)
|
||||
if((Get-SettingValue "AddIDToExportFile") -eq $true -and $obj.Id)
|
||||
{
|
||||
$fileName = ($fileName + "_" + $obj.Id)
|
||||
}
|
||||
$fileName = "$path\$((Remove-InvalidFileNameChars $fileName)).json"
|
||||
if([IO.File]::Exists($fileName) -eq $false)
|
||||
{
|
||||
Write-Log "File not found: $fileName. Could not add assignments" 3
|
||||
Write-Log "File not found: $fileName. Could not add assignments to file" 3
|
||||
return
|
||||
}
|
||||
$tmpObj = Get-Content -LiteralPath $fileName | ConvertFrom-Json
|
||||
|
||||
@@ -10,7 +10,7 @@ This module manages Application objects in Intune e.g. uploading application fil
|
||||
#>
|
||||
function Get-ModuleVersion
|
||||
{
|
||||
'3.1.1'
|
||||
'3.1.2'
|
||||
}
|
||||
|
||||
#########################################################################################
|
||||
@@ -42,6 +42,12 @@ function Get-MSIFileInformation
|
||||
|
||||
$values = @{}
|
||||
|
||||
if(-not $MSIFile) { return }
|
||||
|
||||
$fi = [IO.FileInfo]$MSIFile
|
||||
|
||||
if($fi.Extension -ne ".msi") { return }
|
||||
|
||||
try
|
||||
{
|
||||
$wiObj = New-Object -ComObject WindowsInstaller.Installer
|
||||
|
||||
@@ -9,7 +9,7 @@ Module for listing Intune assignments
|
||||
#>
|
||||
function Get-ModuleVersion
|
||||
{
|
||||
'1.0.2'
|
||||
'1.0.3'
|
||||
}
|
||||
|
||||
function Invoke-InitializeModule
|
||||
@@ -231,10 +231,13 @@ function Invoke-IntueAssignmentFilterBoxChanged
|
||||
$txtBox.Tag = 1
|
||||
$txtBox.Text = "Filter"
|
||||
$txtBox.Foreground="Lightgray"
|
||||
}
|
||||
elseif($txtBox.Tag -eq "1" -and $txtBox.Text -eq "Filter" -and $txtBox.IsFocused -eq $false)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if($txtBox.Tag -eq "1" -and $txtBox.Text -eq "Filter" -and $txtBox.IsFocused -eq $false) { return }
|
||||
$txtBox.FontStyle = "Normal"
|
||||
$txtBox.Tag = $null
|
||||
$txtBox.Foreground="Black"
|
||||
@@ -245,15 +248,15 @@ function Invoke-IntueAssignmentFilterBoxChanged
|
||||
$filter = {
|
||||
param ($item)
|
||||
|
||||
return ( $item.Name -match [regex]::Escape($txtBox.Text) -or $item.IncludedString -match [regex]::Escape($txtBox.Text) -or $item.ExcludedString -match [regex]::Escape($txtBox.Text) )
|
||||
return ($item.Name -match [regex]::Escape($txtBox.Text) -or $item.IncludedString -match [regex]::Escape($txtBox.Text) -or $item.ExcludedString -match [regex]::Escape($txtBox.Text) )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($dgObject.ItemsSource -is [System.Windows.Data.ListCollectionView])
|
||||
if($dgObject.ItemsSource -is [System.Windows.Data.ListCollectionView] -and $txtBox.IsFocused -eq $true)
|
||||
{
|
||||
# This causes odd behaviour with focus e.g. and item has to be clicked twice to be selected
|
||||
$dgObject.ItemsSource.Filter = $filter
|
||||
$dgObject.ItemsSource.Refresh()
|
||||
#$dgObject.ItemsSource.Refresh()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ $global:EMToolsViewObject = $null
|
||||
|
||||
function Get-ModuleVersion
|
||||
{
|
||||
'1.0.2'
|
||||
'1.0.3'
|
||||
}
|
||||
|
||||
function Invoke-InitializeModule
|
||||
@@ -890,10 +890,13 @@ function Invoke-ADMXFilterPolicies
|
||||
$txtBox.Tag = 1
|
||||
$txtBox.Text = "Filter"
|
||||
$txtBox.Foreground="Lightgray"
|
||||
}
|
||||
elseif($txtBox.Tag -eq "1" -and $txtBox.Text -eq "Filter" -and $txtBox.IsFocused -eq $false)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if($txtBox.Tag -eq "1" -and $txtBox.Text -eq "Filter" -and $txtBox.IsFocused -eq $false) { return }
|
||||
$txtBox.FontStyle = "Normal"
|
||||
$txtBox.Tag = $null
|
||||
$txtBox.Foreground="Black"
|
||||
@@ -908,11 +911,11 @@ function Invoke-ADMXFilterPolicies
|
||||
}
|
||||
}
|
||||
|
||||
if($global:dgADMXSettings.ItemsSource -is [System.Windows.Data.ListCollectionView])
|
||||
if($global:dgADMXSettings.ItemsSource -is [System.Windows.Data.ListCollectionView] -and $txtBox.IsFocused -eq $true)
|
||||
{
|
||||
# This causes odd behaviour with focus e.g. and item has to be clicked twice to be selected
|
||||
$global:dgADMXSettings.ItemsSource.Filter = $filter
|
||||
$global:dgADMXSettings.ItemsSource.Refresh()
|
||||
#$global:dgADMXSettings.ItemsSource.Refresh()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ This module manages Authentication for the application with MSAL. It is also res
|
||||
#>
|
||||
function Get-ModuleVersion
|
||||
{
|
||||
'3.3.1'
|
||||
'3.3.2'
|
||||
}
|
||||
|
||||
$global:msalAuthenticator = $null
|
||||
@@ -121,6 +121,14 @@ function Invoke-InitializeModule
|
||||
DefaultValue = "gcc"
|
||||
}) "MSAL"
|
||||
|
||||
Add-SettingsObject (New-Object PSObject -Property @{
|
||||
Title = "Sort Account List"
|
||||
Key = "SortAccountList"
|
||||
Type = "Boolean"
|
||||
DefaultValue = $false
|
||||
Description = "Sort the list of cached accounts based on user name. Updated at restart or account change"
|
||||
}) "MSAL"
|
||||
|
||||
Add-MSALPrereq
|
||||
|
||||
#$script:MSALDLLMissing = $true #!!!!
|
||||
@@ -1389,13 +1397,21 @@ function Get-MSALProfileEllipse
|
||||
[System.Windows.Controls.Canvas]::SetTop($obj,($point.Y + $obj.Tag.ActualHeight))
|
||||
})
|
||||
|
||||
$otherLogins = $global:grdProfileInfo.FindName("grdAccountsAndTenants")
|
||||
$otherLogins = $global:grdProfileInfo.FindName("grdCachedAccounts")
|
||||
|
||||
#########################################################################################################
|
||||
### Add cached users
|
||||
#########################################################################################################
|
||||
if((Get-SettingValue "SortAccountList") -eq $true)
|
||||
{
|
||||
$accounts = $global:MSALAccounts | Sort -Property Username
|
||||
}
|
||||
else
|
||||
{
|
||||
$accounts = $global:MSALAccounts
|
||||
}
|
||||
|
||||
foreach($account in $global:MSALAccounts)
|
||||
foreach($account in $accounts)
|
||||
{
|
||||
# Skip current logged on user
|
||||
if($global:MSALToken.Account.Username -eq $Account.Username) { continue }
|
||||
@@ -1518,9 +1534,13 @@ function Get-MSALProfileEllipse
|
||||
Show-GraphObjects
|
||||
}
|
||||
Write-Status ""
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
$otherLogins = $global:grdProfileInfo.FindName("grdLoginAccount")
|
||||
|
||||
Add-GridObject $otherLogins $lnkButton
|
||||
|
||||
$otherLogins = $global:grdProfileInfo.FindName("grdTenantAccounts")
|
||||
|
||||
if(($script:AccessableTenants | measure).Count -gt 1)
|
||||
{
|
||||
|
||||
@@ -10,7 +10,7 @@ This module manages Microsoft Grap fuctions like calling APIs, managing graph ob
|
||||
#>
|
||||
function Get-ModuleVersion
|
||||
{
|
||||
'3.1.9'
|
||||
'3.1.10'
|
||||
}
|
||||
|
||||
$global:MSGraphGlobalApps = @(
|
||||
@@ -158,7 +158,24 @@ function Invoke-InitializeModule
|
||||
Type = "Boolean"
|
||||
DefaultValue = $false
|
||||
Description = "This will add object ID to the export file to support objects with the same name e.g. ObjectName_ObjectId.json"
|
||||
}) "ImportExport"
|
||||
}) "ImportExport"
|
||||
|
||||
Add-SettingsObject (New-Object PSObject -Property @{
|
||||
Title = "Use Batch API (Preview)"
|
||||
Key = "UseBatchAPI"
|
||||
Type = "Boolean"
|
||||
DefaultValue = $false
|
||||
Description = "This will use batch API to call up to extport 20 objects on each API call"
|
||||
}) "ImportExport"
|
||||
|
||||
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"
|
||||
}) "ImportExport"
|
||||
|
||||
}
|
||||
|
||||
function Get-GraphAppInfo
|
||||
@@ -240,6 +257,12 @@ function Invoke-GraphRequest
|
||||
[switch]
|
||||
$AllPages,
|
||||
|
||||
[int]
|
||||
$PageSize = -1,
|
||||
|
||||
[switch]
|
||||
$Batch,
|
||||
|
||||
[switch]
|
||||
$NoError
|
||||
)
|
||||
@@ -313,12 +336,8 @@ function Invoke-GraphRequest
|
||||
$Url = $Url -replace "%OrganizationId%", $global:Organization.Id
|
||||
}
|
||||
|
||||
<#
|
||||
if($AllPages)
|
||||
{
|
||||
# Code to test paging - Force each page to size specified in top parameter below
|
||||
# Kept for reference
|
||||
|
||||
if($PageSize -gt 0 -and $url.IndexOf("`$top=") -eq -1)
|
||||
{
|
||||
if(($url.IndexOf('?')) -eq -1)
|
||||
{
|
||||
$url = "$($url.Trim())?"
|
||||
@@ -327,9 +346,8 @@ function Invoke-GraphRequest
|
||||
{
|
||||
$url = "$($url.Trim())&"
|
||||
}
|
||||
$url = "$($url.Trim())`$top=20"
|
||||
$url = "$($url.Trim())`$top=$($PageSize)"
|
||||
}
|
||||
#>
|
||||
|
||||
$ret = $null
|
||||
try
|
||||
@@ -390,13 +408,15 @@ function Get-GraphObjects
|
||||
$exclude,
|
||||
$SortProperty = "displayName",
|
||||
$objectType,
|
||||
[string]
|
||||
$select,
|
||||
[switch]
|
||||
$SinglePage,
|
||||
[switch]
|
||||
$AllPages,
|
||||
[switch]
|
||||
$SingleObject)
|
||||
|
||||
$objects = @()
|
||||
|
||||
if($property -isnot [Object[]]) { $property = @('displayName', 'description', 'id')}
|
||||
|
||||
|
||||
$params = @{}
|
||||
if($objectType.ODataMetadata)
|
||||
{
|
||||
@@ -417,15 +437,35 @@ function Get-GraphObjects
|
||||
else
|
||||
{
|
||||
$url = "$($url.Trim())&$($objectType.QUERYLIST.Trim())" # Risky...does not check that the parameter is already in use
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(($url.IndexOf("`$select=")) -eq -1 -and $select)
|
||||
{
|
||||
$url += (?: (($url.IndexOf('?')) -eq -1) "?" "&")
|
||||
$url += "`$select=$select"
|
||||
}
|
||||
|
||||
if($SingleObject -ne $true)
|
||||
if($SinglePage -eq $true)
|
||||
{
|
||||
#Use default page size or use below for a specific page size for testing
|
||||
#$params.Add("pageSize",100)
|
||||
}
|
||||
elseif($SingleObject -ne $true -and $SinglePage -ne $true)
|
||||
{
|
||||
$params.Add('AllPages',$true)
|
||||
}
|
||||
|
||||
if($script:nextGraphPage -and ($SinglePage -eq $true -or $AllPages -eq $true))
|
||||
{
|
||||
$url = $script:nextGraphPage
|
||||
}
|
||||
|
||||
$graphObjects = Invoke-GraphRequest -Url $url @params
|
||||
if($SinglePage -eq $true -or $AllPages -eq $true)
|
||||
{
|
||||
$script:nextGraphPage = $graphObjects.'@odata.nextLink'
|
||||
}
|
||||
|
||||
if($SingleObject -ne $true -and $objectType.PostListCommand)
|
||||
{
|
||||
@@ -441,6 +481,56 @@ function Get-GraphObjects
|
||||
$retObjects = $graphObjects
|
||||
}
|
||||
|
||||
return (Add-GraphObectProperties $retObjects $objectType $property $SortProperty)
|
||||
|
||||
$objects = @()
|
||||
|
||||
foreach($graphObject in $retObjects)
|
||||
{
|
||||
$params = @{}
|
||||
if($property) { $params.Add("Property", $property) }
|
||||
if($exclude) { $params.Add("ExcludeProperty", $exclude) }
|
||||
foreach($objTmp in ($graphObject | Select-Object @params))
|
||||
{
|
||||
$objTmp | Add-Member -NotePropertyName "IsSelected" -NotePropertyValue $false
|
||||
$objTmp | Add-Member -NotePropertyName "Object" -NotePropertyValue $graphObject
|
||||
$objTmp | Add-Member -NotePropertyName "ObjectType" -NotePropertyValue $objectType
|
||||
$objects += $objTmp
|
||||
}
|
||||
}
|
||||
$property = "IsSelected",$property
|
||||
|
||||
if($objects.Count -gt 0 -and $SortProperty -and ($objects[0] | GM -MemberType NoteProperty -Name $SortProperty))
|
||||
{
|
||||
$objects = $objects | sort -Property $SortProperty
|
||||
}
|
||||
|
||||
$objects
|
||||
}
|
||||
|
||||
function Add-GraphObectProperties
|
||||
{
|
||||
param($graphObjects,
|
||||
$objectType,
|
||||
[Array]
|
||||
$property = $null,
|
||||
[Array]
|
||||
$exclude,
|
||||
$SortProperty = "displayName")
|
||||
|
||||
if($property -isnot [Object[]]) { $property = @('displayName', 'description', 'id')}
|
||||
|
||||
$objects = @()
|
||||
|
||||
if($graphObjects -and ($graphObjects | GM -Name Value -MemberType NoteProperty))
|
||||
{
|
||||
$retObjects = $graphObjects.Value
|
||||
}
|
||||
else
|
||||
{
|
||||
$retObjects = $graphObjects
|
||||
}
|
||||
|
||||
foreach($graphObject in $retObjects)
|
||||
{
|
||||
$params = @{}
|
||||
@@ -460,6 +550,7 @@ function Get-GraphObjects
|
||||
{
|
||||
$objects = $objects | sort -Property $SortProperty
|
||||
}
|
||||
|
||||
$objects
|
||||
}
|
||||
|
||||
@@ -505,13 +596,15 @@ function Show-GraphObjects
|
||||
$global:grdTitle.Visibility = "Visible"
|
||||
}
|
||||
|
||||
$graphObjects = @(Get-GraphObjects -property $global:curObjectType.ViewProperties -objectType $global:curObjectType)
|
||||
$script:nextGraphPage = $null
|
||||
|
||||
$graphObjects = @(Get-GraphObjects -property $global:curObjectType.ViewProperties -objectType $global:curObjectType -SinglePage)
|
||||
|
||||
$dgObjects.AutoGenerateColumns = $false
|
||||
$dgObjects.Columns.Clear()
|
||||
|
||||
if(($graphObjects | measure).Count -gt 0)
|
||||
{
|
||||
{
|
||||
$tmpObj = $graphObjects | Select -First 1
|
||||
|
||||
$prop = $tmpObj.PSObject.Properties | Where Name -eq "IsSelected"
|
||||
@@ -526,6 +619,7 @@ function Show-GraphObjects
|
||||
$item.IsSelected = $this.IsChecked
|
||||
}
|
||||
$global:dgObjects.Items.Refresh()
|
||||
Invoke-ModuleFunction "Invoke-EMSelectedItemsChanged"
|
||||
})
|
||||
}
|
||||
|
||||
@@ -585,6 +679,7 @@ function Show-GraphObjects
|
||||
$dgObjects.ItemsSource = $null
|
||||
}
|
||||
|
||||
|
||||
# Show/Hide buttons based on object type
|
||||
foreach($ctrl in $spSubMenu.Children)
|
||||
{
|
||||
@@ -604,6 +699,16 @@ function Show-GraphObjects
|
||||
$ctrl.Visibility = "Collapsed"
|
||||
}
|
||||
}
|
||||
|
||||
Set-GraphPagesButtonStatus
|
||||
}
|
||||
|
||||
function Set-GraphPagesButtonStatus
|
||||
{
|
||||
$global:btnLoadAllPages.Visibility = (?: ($script:nextGraphPage) "Visible" "Collapsed")
|
||||
$global:btnLoadNextPage.Visibility = (?: ($script:nextGraphPage) "Visible" "Collapsed")
|
||||
$global:btnLoadAllPages.Tag = $script:nextGraphPage
|
||||
$global:btnLoadNextPage.Tag = $script:nextGraphPage
|
||||
}
|
||||
|
||||
function Clear-GraphObjects
|
||||
@@ -620,7 +725,7 @@ function Clear-GraphObjects
|
||||
|
||||
function Get-GraphObject
|
||||
{
|
||||
param($obj, $objectType, [switch]$SkipAssignments)
|
||||
param($obj, $objectType, [switch]$SkipAssignments, [switch]$GetAPI)
|
||||
|
||||
Write-Status "Loading $((Get-GraphObjectName $obj $objectType))"
|
||||
|
||||
@@ -696,6 +801,16 @@ function Get-GraphObject
|
||||
$api = ($api + ($expand -join ","))
|
||||
}
|
||||
|
||||
if($global:Organization.Id)
|
||||
{
|
||||
$api = $api -replace "%OrganizationId%", $global:Organization.Id
|
||||
}
|
||||
|
||||
if($GetAPI -eq $true)
|
||||
{
|
||||
return $api
|
||||
}
|
||||
|
||||
$objInfo = Get-GraphObjects -Url $api -property $objectType.ViewProperties -objectType $objectType -SingleObject
|
||||
|
||||
if($objInfo -and $objectType.PostGetCommand)
|
||||
@@ -959,18 +1074,38 @@ function Show-GraphBulkExportForm
|
||||
{
|
||||
$folder = Get-GraphObjectFolder $item.ObjectType (Get-XamlProperty $script:exportForm "txtExportPath" "Text") (Get-XamlProperty $script:exportForm "chkAddObjectType" "IsChecked") (Get-XamlProperty $script:exportForm "chkAddCompanyName" "IsChecked")
|
||||
|
||||
$objects = @(Get-GraphObjects -property $item.ObjectType.ViewProperties -objectType $item.ObjectType)
|
||||
foreach($obj in $objects)
|
||||
Write-Status "Get a list of all $($item.ObjectType.Title) objects" -SkipLog -Force
|
||||
$objects = @(Get-GraphObjects -property $item.ObjectType.ViewProperties -objectType $item.ObjectType)
|
||||
|
||||
if((Get-SettingValue "UseBatchAPI") -eq $true)
|
||||
{
|
||||
$objName = Get-GraphObjectName $obj.Object $obj.ObjectType
|
||||
|
||||
if($txtNameFilter -and $objName -notmatch [RegEx]::Escape($txtNameFilter))
|
||||
# Use batch to get details of each object
|
||||
$batchObjects = Get-GraphBatchObjects $objects $txtNameFilter
|
||||
$i = 1
|
||||
$total = ($batchObjects | measure).Count
|
||||
foreach($batchResult in $batchObjects)
|
||||
{
|
||||
continue
|
||||
}
|
||||
$objName = Get-GraphObjectName $batchResult.Object $batchResult.ObjectType
|
||||
Write-Status "Export $($item.Title): $objName ($($i)/$($total))" -Force
|
||||
Export-GraphObject $batchResult.Object $batchResult.ObjectType $folder -IsFullObject
|
||||
$i++
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach($obj in $objects)
|
||||
{
|
||||
# Export objects one by one
|
||||
$objName = Get-GraphObjectName $obj.Object $obj.ObjectType
|
||||
|
||||
Write-Status "Export $($item.Title): $objName" -Force
|
||||
Export-GraphObject $obj.Object $item.ObjectType $folder
|
||||
if($txtNameFilter -and $objName -notmatch [RegEx]::Escape($txtNameFilter))
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
Write-Status "Export $($item.Title): $objName" -Force
|
||||
Export-GraphObject $obj.Object $item.ObjectType $folder
|
||||
}
|
||||
}
|
||||
Save-Setting "" "LastUsedFullPath" $folder
|
||||
}
|
||||
@@ -2288,13 +2423,21 @@ function Export-GraphObject
|
||||
{
|
||||
param($objToExport,
|
||||
$objectType,
|
||||
$exportFolder)
|
||||
$exportFolder,
|
||||
[switch]$IsFullObject)
|
||||
|
||||
if(-not $exportFolder) { return }
|
||||
|
||||
Write-Status "Export $((Get-GraphObjectName $objToExport $objectType))"
|
||||
|
||||
$obj = Get-GraphExportObject $objToExport $objectType
|
||||
if($IsFullObject -eq $true)
|
||||
{
|
||||
$obj = $objToExport
|
||||
}
|
||||
else
|
||||
{
|
||||
$obj = Get-GraphExportObject $objToExport $objectType
|
||||
}
|
||||
|
||||
if(-not $obj)
|
||||
{
|
||||
@@ -2315,7 +2458,7 @@ function Export-GraphObject
|
||||
}
|
||||
|
||||
$fileName = Get-GraphObjectName $obj $objectType
|
||||
if((Get-SettingValue "AddIDToExportFile") -eq $true -and $obj.Id)
|
||||
if((Get-SettingValue "AddIDToExportFile") -eq $true -and $obj.Id -and $objectType.SkipAddIDOnExport -ne $true)
|
||||
{
|
||||
$fileName = ($fileName + "_" + $obj.Id)
|
||||
}
|
||||
@@ -2335,6 +2478,83 @@ function Export-GraphObject
|
||||
}
|
||||
}
|
||||
|
||||
function Get-GraphBatchObjects
|
||||
{
|
||||
param($objects, $txtNameFilter)
|
||||
|
||||
$curBatch = 1
|
||||
$batchArr = @()
|
||||
$batchResults = @()
|
||||
$batchTotal = 0
|
||||
$objectType = $null
|
||||
foreach($obj in $objects)
|
||||
{
|
||||
$objectType = $obj.ObjectType
|
||||
$objName = Get-GraphObjectName $obj.Object $obj.ObjectType
|
||||
|
||||
if($objName -and $txtNameFilter -and $objName -notmatch [RegEx]::Escape($txtNameFilter))
|
||||
{
|
||||
$batchTotal++
|
||||
}
|
||||
else
|
||||
{
|
||||
$ometadata = ?? $obj.ObjectType.ODataMetadata "Full"
|
||||
$batchArr += [PSCustomObject]@{
|
||||
id = ($batchArr.Count + 1)
|
||||
method = "GET"
|
||||
url = (Get-GraphObject $obj.Object $obj.ObjectType -GetAPI)
|
||||
headers = @{"Accept"="application/json;odata.metadata=$ometadata"}
|
||||
}
|
||||
}
|
||||
|
||||
if($batchArr.Count -eq 20 -or ($batchTotal + $batchArr.Count -eq $objects.Count))
|
||||
{
|
||||
$batchObj = [PSCustomObject]@{
|
||||
requests = $batchArr
|
||||
}
|
||||
|
||||
Write-Status "Get batch $curBatch $($obj.ObjectType.Title)" -Force
|
||||
$batchTotal += $batchArr.Count
|
||||
$json = $batchObj | ConvertTo-Json -Depth 10
|
||||
$tmpResults = Invoke-GraphRequest -Url "`$batch" -Content $json -HttpMethod "POST" -Batch #-Url $api -property $obj.ObjectType.ViewProperties -objectType $obj.ObjectType -
|
||||
$curResp = 1
|
||||
foreach($batchResult in ($tmpResults.responses | Sort -Property Id))
|
||||
{
|
||||
if($batchResult.Status -ne "200" -or -not $batchResult.body)
|
||||
{
|
||||
$reqObj = $batchObj.requests | where id -eq $batchResult.Id
|
||||
Write-Log "Batch result $($batchResult.Status) for URL $($reqObj.URL). Skipping..." 2
|
||||
continue
|
||||
}
|
||||
|
||||
$batchResults += $batchResult.body
|
||||
$curResp++
|
||||
}
|
||||
|
||||
$curBatch++
|
||||
$batchArr = @()
|
||||
}
|
||||
}
|
||||
|
||||
if($objectType -and $batchResults.Count -gt 0)
|
||||
{
|
||||
$batchResultsTmp = $batchResults
|
||||
$batchResults = Add-GraphObectProperties $batchResultsTmp $objectType -property $objectType.ViewProperties
|
||||
|
||||
$curObj = 1
|
||||
foreach($obj in $batchResults)
|
||||
{
|
||||
if($obj.Object -and $obj.ObjectType.PostGetCommand)
|
||||
{
|
||||
Write-Status "Get full info - $((Get-GraphObjectName $obj.Object $obj.ObjectType)) ($($curObj)/$(@($batchResults).Count))" -Force
|
||||
& $obj.ObjectType.PostGetCommand $obj $obj.ObjectType
|
||||
}
|
||||
$curObj++
|
||||
}
|
||||
}
|
||||
$batchResults
|
||||
}
|
||||
|
||||
function Get-GraphExportObject
|
||||
{
|
||||
param($obj, $objectType)
|
||||
@@ -2527,7 +2747,10 @@ function Copy-GraphObject
|
||||
{
|
||||
if((& $global:curObjectType.PreCopyCommand $exportObj $global:curObjectType $ret))
|
||||
{
|
||||
Show-GraphObjects
|
||||
if((Get-SettingValue "RefreshObjectsAfterCopy") -eq $true)
|
||||
{
|
||||
Show-GraphObjects
|
||||
}
|
||||
Write-Status ""
|
||||
return
|
||||
}
|
||||
@@ -2547,7 +2770,10 @@ function Copy-GraphObject
|
||||
{
|
||||
& $global:curObjectType.PostCopyCommand $exportObj $newObj $global:curObjectType
|
||||
}
|
||||
Show-GraphObjects
|
||||
if((Get-SettingValue "RefreshObjectsAfterCopy") -eq $true)
|
||||
{
|
||||
Show-GraphObjects
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2674,4 +2900,75 @@ function Add-GraphBulkMenu
|
||||
$menuItem.AddChild($subItem) | Out-Null
|
||||
|
||||
$mnuMain.Items.Insert(1,$menuItem) | Out-Null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function Get-GraphAllEntityTypes
|
||||
{
|
||||
param($entityType, $xml, $hashTable)
|
||||
|
||||
if(-not $hashTable.ContainsKey($entityType))
|
||||
{
|
||||
$hashTable.Add($entityType, $xml.SelectSingleNode("//*[name()='EntityType' and @Name='$entityType']"))
|
||||
}
|
||||
|
||||
$nodes = $xml.SelectNodes("//*[@BaseType='graph.$entityType']")
|
||||
|
||||
foreach($node in $nodes)
|
||||
{
|
||||
if($node.Abstract -ne "true")
|
||||
{
|
||||
$hashTable.Add($node.Name, $node)
|
||||
}
|
||||
Get-GraphAllEntityTypes $node.Name $xml $hashTable
|
||||
}
|
||||
}
|
||||
|
||||
function Get-GraphEntityTypeObject
|
||||
{
|
||||
param($entityType, $xml, $skipProperties = @())
|
||||
|
||||
$props = Get-GraphEntityTypeProperties $entityType $xml
|
||||
|
||||
if(-not $props) { return }
|
||||
|
||||
$obj = [PSCustomObject]@{
|
||||
|
||||
}
|
||||
|
||||
foreach($prop in $props)
|
||||
{
|
||||
if($prop.Name -in $skipProperties) { continue }
|
||||
$obj | Add-Member -NotePropertyName $prop.Name -NotePropertyValue $null
|
||||
}
|
||||
$obj
|
||||
}
|
||||
|
||||
function Get-GraphEntityTypeProperties
|
||||
{
|
||||
param($entityType, $xml)
|
||||
|
||||
$tmpEntity = $xml.SelectSingleNode("//*[name()='EntityType' and @Name='$entityType']")
|
||||
if(-not $tmpEntity) { return }
|
||||
|
||||
$entities = @()
|
||||
$entities += $tmpEntity
|
||||
|
||||
while($tmpEntity.BaseType)
|
||||
{
|
||||
$baseType = $tmpEntity.BaseType.Split('.')[-1]
|
||||
$tmpEntity = $xml.SelectSingleNode("//*[name()='EntityType' and @Name='$baseType']")
|
||||
if($tmpEntity)
|
||||
{
|
||||
$entities += $tmpEntity
|
||||
}
|
||||
}
|
||||
$properties = @()
|
||||
[array]::Reverse($entities)
|
||||
foreach($enitiy in $entities)
|
||||
{
|
||||
$properties += $enitiy.SelectNodes("*[name()='Property']")
|
||||
}
|
||||
|
||||
$properties
|
||||
}
|
||||
|
||||
@@ -275,7 +275,8 @@ When multi tenant settings is Enabled/Disabled, the Profile Info is not updated
|
||||
|
||||
The *List Applications* API might not list an imported app immediately after the import. Click *Refresh* to reload the application objects.
|
||||
|
||||
When using the filter box to search for items, the checkbox must be clicked twice to select an item.
|
||||
~~When using the filter box to search for items, the checkbox must be clicked twice to select an item.~~</br />
|
||||
Issue fixed in 3.3.2
|
||||
|
||||
Logout will only clear the token from cache and not from the browser e.g. if login is triggered after a logout, the user will still be listed in the 'Select user' dialog.
|
||||
|
||||
|
||||
@@ -1,5 +1,44 @@
|
||||
# Release Notes
|
||||
|
||||
## 3.3.2 - 2021-12-14
|
||||
|
||||
**New features**
|
||||
|
||||
- Markdown support for documentation (Experimental)
|
||||
This will create a MD document in the Documents folder.
|
||||
**Note:** This is not working 100% at the moment. The script will create a MD document but it might be too large if all objects in the environment are documented.
|
||||
|
||||
Also note that HTML tables are used so that code can be documented as code blocks. This must be supported by the MD Viewer. The *Markdown Viewer* extension in Chrome was used during testing.
|
||||
|
||||
Please report any suggestions to the issue.<br />
|
||||
This is based on [Issue 35](https://github.com/Micke-K/IntuneManagement/issues/35)
|
||||
|
||||
- Added support for batched export
|
||||
This will use batch API to request full info for up to 20 objects per batch to reduce export time
|
||||
This can be enabled in setting
|
||||
|
||||
- Added support for scrolling cached users and guest accounts in the profile info<br />
|
||||
This can be enabled in settings
|
||||
|
||||
- Added support for sorting cached users<br />
|
||||
This can be enabled in settings
|
||||
|
||||
**Fixes**
|
||||
|
||||
- Paged return of objects<br />
|
||||
Only first page of objects will be loaded by default.
|
||||
Additional pages can be loaded with **Load More** or all available objects can be loaded with **Load All**.<br />
|
||||
This is based on [Issue 28](https://github.com/Micke-K/IntuneManagement/issues/28)
|
||||
|
||||
- Fixed an issue where a checkbox had to be clicked twice to be checked when the list was filtered <br />
|
||||
This is based on a known issue
|
||||
|
||||
- Fixed an issue where buttons were not enabled when **Select All** was checked<br />
|
||||
This is based on [Issue 36](https://github.com/Micke-K/IntuneManagement/issues/36)
|
||||
|
||||
- Fixed an issue when adding object ID to the file name during export
|
||||
The separate settings file was not exported with the ID in the name which could cause issues during import
|
||||
|
||||
## 3.3.1 (Beta) - 2021-10-28
|
||||
|
||||
This is a **BETA** release. It contains core changes for Authentication and Settings management. Please report any issues [here](https://github.com/Micke-K/IntuneManagement/issues).
|
||||
|
||||
@@ -14,7 +14,13 @@
|
||||
SelectionUnit="FullRow"
|
||||
CanUserAddRows="False"
|
||||
Grid.Column="1"
|
||||
Grid.Row="1" />
|
||||
Grid.Row="1">
|
||||
<DataGrid.Resources>
|
||||
<Style TargetType="{x:Type TextBlock}">
|
||||
<Setter Property="TextWrapping" Value="NoWrap"/>
|
||||
</Style>
|
||||
</DataGrid.Resources>
|
||||
</DataGrid>
|
||||
|
||||
<Grid Name="grdTitle" Visibility="Collapsed" >
|
||||
<Grid.ColumnDefinitions>
|
||||
@@ -22,13 +28,17 @@
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Border Background="{DynamicResource TitleBackgroundColor}" Margin="0,0,0,5" >
|
||||
<ContentControl Name="ccIcon" Width="24" Height="24" Margin="5,0,0,0" />
|
||||
</Border>
|
||||
<TextBlock Name="txtFormTitle" Text="" Grid.Column="1" Grid.ColumnSpan="3" FontWeight="Bold" Padding="5" Margin="0,0,0,5" Background="{DynamicResource TitleBackgroundColor}" />
|
||||
<TextBox Name="txtFilter" Grid.Column="2" MinWidth="200" MaxHeight="20" Margin="0,0,5,3" />
|
||||
<TextBlock Name="txtFormTitle" Text="" Grid.Column="1" Grid.ColumnSpan="5" FontWeight="Bold" Padding="5" Margin="0,0,0,5" Background="{DynamicResource TitleBackgroundColor}" />
|
||||
<Button Name="btnLoadAllPages" Grid.Column="2" Content="Load All" Width='100' Margin="0,5,5,7" Visibility="Collapsed" />
|
||||
<Button Name="btnLoadNextPage" Grid.Column="3" Content="Load More" Width='100' Margin="0,5,5,7" Visibility="Collapsed" />
|
||||
<TextBox Name="txtFilter" Grid.Column="4" MinWidth="200" MaxHeight="20" Margin="0,0,5,3" />
|
||||
<!--
|
||||
<Grid Grid.Column="2" MinWidth="200" MaxHeight="20">
|
||||
<TextBlock Text="Filter" Background="White" />
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
@@ -46,10 +48,27 @@
|
||||
<Button Margin="5" Name="lnkForceRefresh" ToolTip="Force a refresh of the token e.g. after being added to a new role" Content="Refresh" Cursor="Hand" Style="{DynamicResource LinkButton}" />
|
||||
</StackPanel>
|
||||
|
||||
<Grid Grid.Row="8" Name="grdAccountsAndTenants" Grid.ColumnSpan="2" Margin="5,0,5,0" HorizontalAlignment="Stretch">
|
||||
<ScrollViewer Grid.Row="8" Grid.ColumnSpan="2" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" MaxHeight="200">
|
||||
<Grid Name="grdCachedAccounts" Margin="5,0,5,2" HorizontalAlignment="Stretch" VerticalAlignment="Top" >
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
|
||||
<Grid Name="grdLoginAccount" Grid.Row="9" Grid.ColumnSpan="2" Margin="5,0,5,0" HorizontalAlignment="Stretch" VerticalAlignment="Top" >
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
</Grid>
|
||||
|
||||
<ScrollViewer Grid.Row="10" Grid.ColumnSpan="2" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" MaxHeight="200">
|
||||
<Grid Name="grdTenantAccounts" Margin="5,0,5,2" HorizontalAlignment="Stretch" VerticalAlignment="Top" >
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
|
||||
</Grid>
|
||||
</Border>
|
||||
Reference in New Issue
Block a user