Files

383 lines
14 KiB
PowerShell

#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).
}
}