mirror of
https://github.com/Micke-K/IntuneManagement.git
synced 2026-09-28 10:55:38 +02:00
IntuneManagement 4.0.0-beta1
This commit is contained in:
@@ -0,0 +1,382 @@
|
||||
#ImportOrder 30
|
||||
|
||||
class CompareProviderBase
|
||||
{
|
||||
[string] $Name
|
||||
[string] $Value
|
||||
[string] $OptionsXaml
|
||||
[string[]] $RemoveProperties = @()
|
||||
[bool] $IgnoreGroups = $false
|
||||
# Skip objects that exist on only one side. Source = the reverse pass
|
||||
# (objects only in the counterpart set); Destination = the forward pass
|
||||
# (objects whose looked-up counterpart is missing). Same semantics as the
|
||||
# original project's Skip Missing Source/Destination Policies checkboxes.
|
||||
[bool] $SkipMissingSourcePolicies = $false
|
||||
[bool] $SkipMissingDestinationPolicies = $false
|
||||
|
||||
CompareProviderBase([string]$name, [string]$value, [string]$optionsXaml)
|
||||
{
|
||||
$this.Name = $name
|
||||
$this.Value = $value
|
||||
$this.OptionsXaml = $optionsXaml
|
||||
}
|
||||
|
||||
[object[]] GetComparePairs([object[]]$groups) { return @() }
|
||||
[bool] Validate() { return $true }
|
||||
[void] SaveSettings() {}
|
||||
[string] ToString() { return $this.Name }
|
||||
}
|
||||
|
||||
class CompareExportFilesProvider : CompareProviderBase
|
||||
{
|
||||
[string] $ExportPath
|
||||
[string] $NameFilter
|
||||
|
||||
CompareExportFilesProvider() : base(
|
||||
"Exported Files with Intune Objects (Id)",
|
||||
"export",
|
||||
"CompareExportOptions"
|
||||
) {}
|
||||
|
||||
[object[]] GetComparePairs([object[]]$groups)
|
||||
{
|
||||
$pairs = @()
|
||||
|
||||
foreach($group in $groups)
|
||||
{
|
||||
foreach($policyType in $group.PolicyTypes)
|
||||
{
|
||||
$folder = [IO.Path]::Combine($this.ExportPath, $policyType.Folder)
|
||||
if(-not [IO.Directory]::Exists($folder))
|
||||
{
|
||||
Write-Log "Folder '$folder' not found. Skipping." 2
|
||||
continue
|
||||
}
|
||||
|
||||
Save-SettingStoreValue "" "LastUsedFullPath" $folder
|
||||
Write-Status "Compare $($policyType.Title)" -Force -SkipLog
|
||||
|
||||
$fileObjs = @(Get-PoliciesFromFolder -Path $folder -PolicyTypes @($policyType))
|
||||
$intuneObjs = @(Get-GraphPolicies -PolicyGroup $group.ID | Where-Object { $_.PolicyType.ID -eq $policyType.ID })
|
||||
|
||||
$pairedFileIds = @()
|
||||
foreach($fileObj in $fileObjs)
|
||||
{
|
||||
$objName = $fileObj.Name
|
||||
if($this.NameFilter -and $objName -notmatch [RegEx]::Escape($this.NameFilter)) { continue }
|
||||
if(-not $fileObj.ID) { Write-Log "File '$objName' has no Id. Skipping." 2; continue }
|
||||
|
||||
$intuneObj = $intuneObjs | Where-Object { $_.ID -eq $fileObj.ID }
|
||||
if($intuneObj) { $policyType.GetFullObject($intuneObj) | Out-Null }
|
||||
elseif($this.SkipMissingDestinationPolicies) { continue }
|
||||
else { Write-Log "Object '$objName' with id $($fileObj.ID) not found in Intune. Deleted?" 2 }
|
||||
|
||||
$pairedFileIds += [string]$fileObj.ID
|
||||
$pairs += [PSCustomObject]@{
|
||||
Name = $objName
|
||||
Id = $fileObj.ID
|
||||
PolicyType = $policyType
|
||||
SaveFolder = $folder
|
||||
Policy1 = $intuneObj
|
||||
Policy2 = $fileObj
|
||||
}
|
||||
}
|
||||
|
||||
if(-not $this.SkipMissingSourcePolicies)
|
||||
{
|
||||
# Objects that exist in Intune but were never exported.
|
||||
foreach($intuneObj in $intuneObjs)
|
||||
{
|
||||
if([string]$intuneObj.ID -in $pairedFileIds) { continue }
|
||||
$objName = $intuneObj.Name
|
||||
if($this.NameFilter -and $objName -notmatch [RegEx]::Escape($this.NameFilter)) { continue }
|
||||
|
||||
Write-Log "Object '$objName' with id $($intuneObj.ID) exists in Intune but has no exported file. New object?" 2
|
||||
$pairs += [PSCustomObject]@{
|
||||
Name = $objName
|
||||
Id = $intuneObj.ID
|
||||
PolicyType = $policyType
|
||||
SaveFolder = $folder
|
||||
Policy1 = $intuneObj
|
||||
Policy2 = $null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $pairs
|
||||
}
|
||||
|
||||
[void] SaveSettings()
|
||||
{
|
||||
# No persisted options: the "Compare\ExportPath" write that used to live here
|
||||
# was never read back anywhere (dead since the port).
|
||||
}
|
||||
}
|
||||
|
||||
class CompareIntuneWithExportProvider : CompareProviderBase
|
||||
{
|
||||
[string] $ExportPath
|
||||
[string] $NameFilter
|
||||
|
||||
CompareIntuneWithExportProvider() : base(
|
||||
"Intune Objects with Exported Files (Name)",
|
||||
"IntuneWithExport",
|
||||
"CompareExportOptions"
|
||||
) {}
|
||||
|
||||
[object[]] GetComparePairs([object[]]$groups)
|
||||
{
|
||||
$pairs = @()
|
||||
|
||||
foreach($group in $groups)
|
||||
{
|
||||
foreach($policyType in $group.PolicyTypes)
|
||||
{
|
||||
$folder = [IO.Path]::Combine($this.ExportPath, $policyType.Folder)
|
||||
if(-not [IO.Directory]::Exists($folder))
|
||||
{
|
||||
Write-Log "Folder '$folder' not found. Skipping." 2
|
||||
continue
|
||||
}
|
||||
|
||||
Save-SettingStoreValue "" "LastUsedFullPath" $folder
|
||||
Write-Status "Compare $($policyType.Title)" -Force -SkipLog
|
||||
|
||||
$fileObjs = @(Get-PoliciesFromFolder -Path $folder -PolicyTypes @($policyType))
|
||||
$intuneObjs = @(Get-GraphPolicies -PolicyGroup $group.ID | Where-Object { $_.PolicyType.ID -eq $policyType.ID })
|
||||
|
||||
$pairedFileNames = @()
|
||||
foreach($intuneObj in $intuneObjs)
|
||||
{
|
||||
$objName = $intuneObj.Name
|
||||
if($this.NameFilter -and $objName -notmatch [RegEx]::Escape($this.NameFilter)) { continue }
|
||||
|
||||
$fileObj = $fileObjs | Where-Object { $_.Name -eq $objName }
|
||||
if(($fileObj | Measure-Object).Count -gt 1)
|
||||
{
|
||||
Write-Log "Multiple file objects with name '$objName'. Skipping." 2
|
||||
continue
|
||||
}
|
||||
|
||||
if($fileObj) {
|
||||
$policyType.GetFullObject($intuneObj) | Out-Null
|
||||
$pairedFileNames += [string]$objName
|
||||
}
|
||||
elseif($this.SkipMissingDestinationPolicies) { continue }
|
||||
else { Write-Log "Object '$objName' with id $($intuneObj.ID) not found in exported folder. New object?" 2 }
|
||||
|
||||
$pairs += [PSCustomObject]@{
|
||||
Name = $objName
|
||||
Id = $intuneObj.ID
|
||||
PolicyType = $policyType
|
||||
SaveFolder = $folder
|
||||
Policy1 = $intuneObj
|
||||
Policy2 = $fileObj
|
||||
}
|
||||
}
|
||||
|
||||
if(-not $this.SkipMissingSourcePolicies)
|
||||
{
|
||||
# Exported files with no matching Intune object.
|
||||
foreach($fileObj in $fileObjs)
|
||||
{
|
||||
$objName = $fileObj.Name
|
||||
if([string]$objName -in $pairedFileNames) { continue }
|
||||
if($this.NameFilter -and $objName -notmatch [RegEx]::Escape($this.NameFilter)) { continue }
|
||||
|
||||
Write-Log "File object '$objName' has no matching Intune object. Deleted?" 2
|
||||
$pairs += [PSCustomObject]@{
|
||||
Name = $objName
|
||||
Id = $fileObj.ID
|
||||
PolicyType = $policyType
|
||||
SaveFolder = $folder
|
||||
Policy1 = $null
|
||||
Policy2 = $fileObj
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $pairs
|
||||
}
|
||||
|
||||
[void] SaveSettings()
|
||||
{
|
||||
# No persisted options: the "Compare\ExportPath" write that used to live here
|
||||
# was never read back anywhere (dead since the port).
|
||||
}
|
||||
}
|
||||
|
||||
class CompareNamedObjectsProvider : CompareProviderBase
|
||||
{
|
||||
[string] $SourcePattern
|
||||
[string] $ComparePattern
|
||||
[string] $SavePath
|
||||
[string[]] $RemoveProperties = @("Id")
|
||||
|
||||
CompareNamedObjectsProvider() : base(
|
||||
"Named Objects in Intune",
|
||||
"name",
|
||||
"CompareNamedOptions"
|
||||
)
|
||||
{
|
||||
$this.RemoveProperties = @("Id")
|
||||
}
|
||||
|
||||
[object[]] GetComparePairs([object[]]$groups)
|
||||
{
|
||||
if(-not $this.SourcePattern -or -not $this.ComparePattern)
|
||||
{
|
||||
throw "Both source and compare name patterns must be specified"
|
||||
}
|
||||
|
||||
$outputFolder = $this.SavePath
|
||||
if(-not $outputFolder) { $outputFolder = [Environment]::GetFolderPath("MyDocuments") }
|
||||
|
||||
$pairs = @()
|
||||
|
||||
foreach($group in $groups)
|
||||
{
|
||||
Write-Status "Compare $($group.Title) objects" -Force -SkipLog
|
||||
$intuneObjs = @(Get-GraphPolicies -PolicyGroup $group.ID)
|
||||
|
||||
foreach($intuneObj in ($intuneObjs | Where-Object { $_.Name -imatch [regex]::Escape($this.SourcePattern) }))
|
||||
{
|
||||
$sourceName = $intuneObj.Name
|
||||
$compareName = $sourceName -ireplace [regex]::Escape($this.SourcePattern), $this.ComparePattern
|
||||
|
||||
$compareObj = $intuneObjs | Where-Object { $_.Name -eq $compareName -and $_.Object.'@OData.Type' -eq $intuneObj.Object.'@OData.Type' }
|
||||
if(($compareObj | Measure-Object).Count -gt 1)
|
||||
{
|
||||
Write-Log "Multiple objects named '$compareName'. Skipping." 2
|
||||
continue
|
||||
}
|
||||
|
||||
if($compareObj)
|
||||
{
|
||||
$intuneObj.PolicyType.GetFullObject($intuneObj) | Out-Null
|
||||
$compareObj.PolicyType.GetFullObject($compareObj) | Out-Null
|
||||
}
|
||||
|
||||
$pairs += [PSCustomObject]@{
|
||||
Name = $sourceName
|
||||
Id = $intuneObj.ID
|
||||
PolicyType = $intuneObj.PolicyType
|
||||
SaveFolder = $outputFolder
|
||||
Policy1 = $intuneObj
|
||||
Policy2 = $compareObj
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $pairs
|
||||
}
|
||||
|
||||
[void] SaveSettings()
|
||||
{
|
||||
# No persisted options: the CompareSource / CompareWith / SavePath writes that
|
||||
# used to live here were never read back anywhere (dead since the port).
|
||||
}
|
||||
}
|
||||
|
||||
class CompareExportedFoldersProvider : CompareProviderBase
|
||||
{
|
||||
[string] $SourcePath
|
||||
[string] $ComparePath
|
||||
[string] $NameFilter
|
||||
|
||||
CompareExportedFoldersProvider() : base(
|
||||
"Files in Exported Folders",
|
||||
"exportedFolders",
|
||||
"CompareExportedFilesOptions"
|
||||
) {}
|
||||
|
||||
[object[]] GetComparePairs([object[]]$groups)
|
||||
{
|
||||
if(-not $this.SourcePath -or -not $this.ComparePath)
|
||||
{
|
||||
throw "Both source and compare folders must be specified"
|
||||
}
|
||||
if(-not [IO.Directory]::Exists($this.SourcePath))
|
||||
{
|
||||
throw "Source folder '$($this.SourcePath)' does not exist"
|
||||
}
|
||||
if(-not [IO.Directory]::Exists($this.ComparePath))
|
||||
{
|
||||
throw "Compare folder '$($this.ComparePath)' does not exist"
|
||||
}
|
||||
|
||||
$pairs = @()
|
||||
|
||||
foreach($group in $groups)
|
||||
{
|
||||
foreach($policyType in $group.PolicyTypes)
|
||||
{
|
||||
$folderSrc = [IO.Path]::Combine($this.SourcePath, $policyType.Folder)
|
||||
$folderCmp = [IO.Path]::Combine($this.ComparePath, $policyType.Folder)
|
||||
|
||||
if(-not [IO.Directory]::Exists($folderSrc)) { Write-Log "Source folder '$folderSrc' not found. Skipping." 2; continue }
|
||||
|
||||
Save-SettingStoreValue "" "LastUsedFullPath" $folderSrc
|
||||
Write-Status "Compare $($policyType.Title)" -Force -SkipLog
|
||||
|
||||
$srcObjs = @(Get-PoliciesFromFolder -Path $folderSrc -PolicyTypes @($policyType))
|
||||
$cmpObjs = @()
|
||||
if([IO.Directory]::Exists($folderCmp))
|
||||
{
|
||||
$cmpObjs = @(Get-PoliciesFromFolder -Path $folderCmp -PolicyTypes @($policyType))
|
||||
}
|
||||
|
||||
$addedIds = @()
|
||||
|
||||
foreach($srcObj in $srcObjs)
|
||||
{
|
||||
$objName = $srcObj.Name
|
||||
if($this.NameFilter -and $objName -notmatch [RegEx]::Escape($this.NameFilter)) { continue }
|
||||
if(-not $srcObj.ID) { Write-Log "File '$objName' has no Id. Skipping." 2; continue }
|
||||
|
||||
$cmpObj = $cmpObjs | Where-Object { $_.ID -eq $srcObj.ID }
|
||||
$addedIds += $srcObj.ID
|
||||
if(-not $cmpObj -and $this.SkipMissingDestinationPolicies) { continue }
|
||||
|
||||
$pairs += [PSCustomObject]@{
|
||||
Name = $objName
|
||||
Id = $srcObj.ID
|
||||
PolicyType = $policyType
|
||||
SaveFolder = $folderSrc
|
||||
Policy1 = $srcObj
|
||||
Policy2 = $cmpObj
|
||||
}
|
||||
}
|
||||
|
||||
foreach($cmpObj in $cmpObjs)
|
||||
{
|
||||
if($this.SkipMissingSourcePolicies) { continue }
|
||||
if($cmpObj.ID -in $addedIds) { continue }
|
||||
$objName = $cmpObj.Name
|
||||
if($this.NameFilter -and $objName -notmatch [RegEx]::Escape($this.NameFilter)) { continue }
|
||||
|
||||
$pairs += [PSCustomObject]@{
|
||||
Name = $objName
|
||||
Id = $cmpObj.ID
|
||||
PolicyType = $policyType
|
||||
SaveFolder = $folderSrc
|
||||
Policy1 = $null
|
||||
Policy2 = $cmpObj
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $pairs
|
||||
}
|
||||
|
||||
[void] SaveSettings()
|
||||
{
|
||||
# No persisted options: the SourcePath / ComparePath writes that used to live
|
||||
# here were never read back anywhere (dead since the port).
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user