This commit is contained in:
Mikael Karlsson
2023-10-17 20:34:44 +11:00
parent ea3af64316
commit ab7b062946
33 changed files with 6545 additions and 4702 deletions

View File

@@ -10,7 +10,7 @@ This module will also document some objects based on PowerShell functions
function Get-ModuleVersion
{
'1.6.1'
'1.6.2'
}
function Invoke-InitializeModule
@@ -2744,6 +2744,28 @@ function Invoke-CDDocumentConditionalAccess
EntityKey = "excludeDevices"
})
}
if($obj.conditions.devices.deviceFilter)
{
if($obj.conditions.devices.deviceFilter.mode -eq "include")
{
$filterMode = "included"
}
else
{
$filterMode = "included"
}
#AzureCA.PolicyBlade.Conditions.DeviceAttributes.AssignmentFilter.Blade
#AzureCA.PolicyBlade.Conditions.DeviceAttributes.Blade.title
Add-CustomSettingObject ([PSCustomObject]@{
Name = Get-LanguageString "AzureCA.PolicyBlade.Conditions.DeviceAttributes.Blade.AppliesTo.$filterMode"
Value = $obj.conditions.devices.deviceFilter.rule
Category = $category
SubCategory = Get-LanguageString "AzureCA.PolicyBlade.Conditions.DeviceAttributes.Blade.title"
EntityKey = "includeDevices"
})
}
###################################################
# Grant

View File

@@ -10,7 +10,7 @@ This module is for the Endpoint Manager/Intune View. It manages Export/Import/Co
#>
function Get-ModuleVersion
{
'3.9.1'
'3.9.2'
}
function Invoke-InitializeModule
@@ -73,6 +73,21 @@ function Invoke-InitializeModule
SubPath = "EndpointManager"
}) "EndpointManager"
Add-SettingsObject (New-Object PSObject -Property @{
Title = "Save Encryption File"
Key = "EMSaveEncryptionFile"
Type = "Boolean"
Description = "Save encryption file when uploading an app. This can then be used to when downloading the app file."
SubPath = "EndpointManager"
}) "EndpointManager"
Add-SettingsObject (New-Object PSObject -Property @{
Title = "App download folder"
Key = "EMIntuneAppDownloadFolder"
Type = "Folder"
Description = "Folder where app packages will be downloaded and where encryption files will be saved"
SubPath = "EndpointManager"
}) "EndpointManager"
$viewPanel = Get-XamlObject ($global:AppRootFolder + "\Xaml\EndpointManagerPanel.xaml") -AddVariables
@@ -314,7 +329,7 @@ function Invoke-InitializeModule
PostFileImportCommand = { Start-PostFileImportAdministrativeTemplate @args }
PreImportCommand = { Start-PreImportAdministrativeTemplate @args }
LoadObject = { Start-LoadAdministrativeTemplate @args }
PropertiesToRemove = @("definitionValues")
PropertiesToRemove = @("definitionValues","policyConfigurationIngestionType")
Permissons=@("DeviceManagementConfiguration.ReadWrite.All")
Icon="DeviceConfiguration"
GroupId = "DeviceConfiguration"
@@ -454,8 +469,10 @@ function Invoke-InitializeModule
PreDeleteCommand = { Start-PreDeleteApplications @args }
PostExportCommand = { Start-PostExportApplications @args }
PostListCommand = { Start-PostListApplications @args }
ExportExtension = { Add-ScriptExportExtensions @args }
ExportExtension = { Add-ScriptExportApplications @args }
PostGetCommand = { Start-PostGetApplications @args }
PostImportCommand = { Start-PostImportApplications @args }
PostFilesImportCommand = { Start-PostFilesImportApplications @args }
GroupId = "Apps"
ScopeTagsReturnedInList = $false
})
@@ -1985,24 +2002,41 @@ function local:Start-ImportApp
if($appType -eq "microsoft.graph.win32LobApp")
{
Copy-Win32LOBPackage $packageFile $obj
$fileEncryptionInfo = Copy-Win32LOBPackage $packageFile $obj
}
elseif($appType -eq "microsoft.graph.windowsMobileMSI")
{
Copy-MSILOB $packageFile $obj
$fileEncryptionInfo = Copy-MSILOB $packageFile $obj
}
elseif($appType -eq "microsoft.graph.iosLOBApp")
{
Copy-iOSLOB $packageFile $obj
$fileEncryptionInfo = Copy-iOSLOB $packageFile $obj
}
elseif($appType -eq "microsoft.graph.androidLOBApp")
{
Copy-AndroidLOB $packageFile $obj
$fileEncryptionInfo = Copy-AndroidLOB $packageFile $obj
}
else
{
Write-Log "Unsupported application type $appType. File will not be uploaded" 2
}
if((Get-SettingValue "EMSaveEncryptionFile") -eq $true)
{
#$fileEncryptionInfo = $fileEncryptionInfo | where { $null -ne $_.fileEncryptionInfo }
if($fileEncryptionInfo)
{
$jsonEncryptionInfo = $fileEncryptionInfo.fileEncryptionInfo | ConvertTo-Json -Depth 10
$pkgPath = Get-SettingValue "EMIntuneAppDownloadFolder" (Get-SettingValue "EMIntuneAppPackages")
if($pkgPath -and [IO.Directory]::Exists($pkgPath))
{
$obj = Invoke-GraphRequest -Url "/deviceAppManagement/mobileApps/$($obj.id)" -ODataMetadata "Minimal"
$fullPath = $pkgPath + "\$($obj.displayName)_$($obj.id)_$($obj.committedContentVersion).json"
$jsonEncryptionInfo | Out-File -FilePath $fullPath -Force -Encoding utf8
}
}
}
}
function Start-PreUpdateApplication
@@ -2092,6 +2126,69 @@ function Add-DetailExtensionApplications
$tmp.Children.Insert($index, $btnUpload)
}
$btnDownload = New-Object System.Windows.Controls.Button
$btnDownload.Content = 'Download'
$btnDownload.Name = 'btnDownloadAppfile'
$btnDownload.Margin = "0,0,5,0"
$btnDownload.Width = "100"
$btnDownload.Add_Click({
Write-Status "Download file"
$obj = $global:dgObjects.SelectedItem.Object
#$obj = Invoke-GraphRequest -Url "/deviceAppManagement/mobileApps/$($obj.id)"
$pkgPath = Get-SettingValue "EMIntuneAppDownloadFolder" (Get-SettingValue "EMIntuneAppPackages")
$dlgSave = [System.Windows.Forms.SaveFileDialog]::new()
$dlgSave.InitialDirectory = $pkgPath
$dlgSave.FileName = ($obj.FileName + ".encrypted")
if($dlgSave.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK -and $dlgSave.Filename)
{
Start-DownloadAppContent $obj $dlgSave.FileName
if([IO.File]::Exists($dlgSave.FileName))
{
$fullPath = $pkgPath + "\$($obj.displayName)_$($obj.id)_$($obj.committedContentVersion).json"
if([IO.File]::Exists($fullPath) -eq $false)
{
if(([System.Windows.MessageBox]::Show("Could not find decryption file for $($obj.displayName)`nApp Id: $($obj.id)`nContent version $($obj.committedContentVersion)`n`nDo you want to browse for the file?", "Encryption file not found", "YesNo", "Warning")) -eq "Yes")
{
$of = [System.Windows.Forms.OpenFileDialog]::new()
$of.InitialDirectory = $pkgPath
$of.DefaultExt = "*.json"
$of.Filter = "Json (*.json)|*.*"
$of.Multiselect = $false
if($of.ShowDialog() -eq "OK")
{
$fullPath = $of.FileName
}
}
}
if([IO.File]::Exists($fullPath))
{
Write-Status "Decrypting file"
$encryptionInfo = ConvertFrom-Json (Get-Content -Path $fullPath -Raw)
$destination = $pkgPath + "\$($obj.FileName)"
Start-DecryptFile $dlgSave.Filename $destination $encryptionInfo.encryptionKey $encryptionInfo.initializationVector
}
else
{
Write-Log "Decryption file for $($obj.displayName) not found. Skipping decryption" 2
}
}
}
Write-Status ""
})
$tmp = $form.FindName($buttonPanel)
if($tmp)
{
$tmp.Children.Insert($index, $btnDownload)
}
}
function Start-PreImportAssignmentsApplications
@@ -2177,6 +2274,42 @@ function Start-PostExportApplications
Write-LogError "Failed to export scripts" $_.Exception
}
}
Save-Setting "Intune" "ExportAppFile" $global:chkExportApplicationFile.IsChecked
if($global:chkExportApplicationFile.IsChecked)
{
$encryptioSource = Get-SettingValue "EMIntuneAppDownloadFolder" (Get-SettingValue "EMIntuneAppPackages")
$pkgPath = $path
if($pkgPath)
{
Write-Status "Download file"
$exportFile = $pkgPath + "\$($obj.FileName).encrypted"
$encryptionFile = $encryptioSource + "\$($obj.displayName)_$($obj.id)_$($obj.committedContentVersion).json"
if($encryptionFile -and [IO.File]::Exists($encryptionFile))
{
Start-DownloadAppContent $obj $exportFile
if([IO.File]::Exists($exportFile))
{
Write-Status "Decrypting file"
$encryptionInfo = ConvertFrom-Json (Get-Content -Path $encryptionFile -Raw)
$destination = $pkgPath + "\$($obj.FileName)"
Start-DecryptFile $exportFile $destination $encryptionInfo.encryptionKey $encryptionInfo.initializationVector
}
try { [IO.File]::Delete($exportFile) }
catch {
Write-LogError "Filed to delete exported encrypted file" $_.Exception
}
}
else
{
Write-Log "Cound not file encryption file `"$($obj.displayName)_$($obj.id)_$($obj.committedContentVersion).json`""
}
}
}
}
function Start-PostListApplications
@@ -2204,26 +2337,174 @@ function Start-PostListApplications
$objList
}
function Add-ScriptExportApplications
{
param($form, $buttonPanel, $index = 0)
Add-ScriptExportExtensions $form $buttonPanel $index
$ctrl = $form.FindName("chkExportApplicationFile")
if(-not $ctrl)
{
$xaml = @"
<StackPanel $($global:wpfNS) Orientation="Horizontal" Margin="0,0,5,0">
<Label Content="Export application file" />
<Rectangle Style="{DynamicResource InfoIcon}" ToolTip="Export the application file. Note: Application file will only be exported if ecryption file is found." />
</StackPanel>
"@
$label = [Windows.Markup.XamlReader]::Parse($xaml)
$global:chkExportApplicationFile = [System.Windows.Controls.CheckBox]::new()
$global:chkExportApplicationFile.IsChecked = ((Get-Setting "Intune" "ExportAppFile" "false") -eq "true")
$global:chkExportApplicationFile.VerticalAlignment = "Center"
$global:chkExportApplicationFile.Name = "chkExportApplicationFile"
@($label, $global:chkExportApplicationFile)
}
}
function Start-PostGetApplications {
param($obj, $objectType)
$relationships = (Invoke-GraphRequest -Url "/deviceAppManagement/mobileApps/$($obj.Id)/relationships?`$filter=targetType%20eq%20microsoft.graph.mobileAppRelationshipType%27child%27").value
$dependencyApps = @()
$supersededApps = @()
foreach ($rel in $relationships) {
if ($rel."@odata.type" -eq "#microsoft.graph.mobileAppDependency") {
$dependencyApps += "$($rel.targetDisplayName)|!|$($rel.targetDisplayVersion)|!|$($rel.targetId)|!|$($rel.dependencyType)"
if($obj.Object.dependentAppCount -is [Int] -and ($obj.Object.dependentAppCount -gt 0 -or $obj.Object.supersededAppCount -gt 0)) {
$relationships = (Invoke-GraphRequest -Url "/deviceAppManagement/mobileApps/$($obj.Id)/relationships?`$filter=targetType%20eq%20microsoft.graph.mobileAppRelationshipType%27child%27").value
$dependencyApps = @()
$supersededApps = @()
foreach ($rel in $relationships) {
if ($rel."@odata.type" -eq "#microsoft.graph.mobileAppDependency") {
$dependencyApps += "$($rel.targetDisplayName)|!|$($rel.targetDisplayVersion)|!|$($rel.targetId)|!|$($rel.dependencyType)"
}
elseif ($rel."@odata.type" -eq "#microsoft.graph.mobileAppSupersedence") {
$supersededApps += "$($rel.targetDisplayName)|!|$($rel.targetDisplayVersion)|!|$($rel.targetId)|!|$($rel.supersedenceType)"
}
}
elseif ($rel."@odata.type" -eq "#microsoft.graph.mobileAppSupersedence") {
$supersededApps += "$($rel.targetDisplayName)|!|$($rel.targetDisplayVersion)|!|$($rel.targetId)|!|$($rel.supersedenceType)"
if ($dependencyApps.Count -gt 0) {
$obj.Object | Add-Member -MemberType NoteProperty -Name "#CustomRefDependency" -Value ($dependencyApps -join "|*|")
}
if ($supersededApps.Count -gt 0) {
$obj.Object | Add-Member -MemberType NoteProperty -Name "#CustomRefSupersedence" -Value ($supersededApps -join "|*|")
}
}
if ($dependencyApps.Count -gt 0) {
$obj.Object | Add-Member -MemberType NoteProperty -Name "#CustomRefDependency" -Value ($dependencyApps -join "|*|")
}
}
function Start-PostImportApplications
{
param($obj, $objectType, $file)
#$tmpObj = Get-GraphObjectFromFile $file
}
function Start-PostFilesImportApplications
{
param($objType, $importedObjects, $importedFiles)
$refObjects = $importedFiles | Where { $null -ne $_.Object."#CustomRefDependency" -or $null -ne $_.Object."#CustomRefSupersedence" }
if ($supersededApps.Count -gt 0) {
$obj.Object | Add-Member -MemberType NoteProperty -Name "#CustomRefSupersedence" -Value ($supersededApps -join "|*|")
if(($refObjects | measure).Count -gt 0)
{
Write-Log "Applicetions with Depnedency or Supersedence detected"
foreach($file in $refObjects)
{
Add-ApplicationReferences $file.ImportedObject $file.Object
}
}
}
function local:Add-ApplicationReferences
{
param($obj, $fileObj)
if($fileObj."#CustomRefDependency" -or $fileObj."#CustomRefSupersedence")
{
Write-Log "Adding app references for $($obj.displayName)"
$depAppsInfo = $fileObj."#CustomRefDependency"
$supAppsInfo = $fileObj."#CustomRefSupersedence"
$releationShips = [PSCustomObject]@{
relationships = @()
}
if($depAppsInfo)
{
foreach($depApp in ($depAppsInfo -split "[|][*][|]"))
{
$appName, $appVer, $appId, $appType = $depApp -split "[|][!][|]"
if(-not $appName -or -not $appVer)
{
Write-Log "Could not get Name and Version from string: $appApp" 2
continue
}
$tmpApps = (Invoke-GraphRequest -Url "/deviceAppManagement/mobileApps?`$filter=displayName eq '$appName'").value
if(-not $tmpApps)
{
Write-Log "No application found with name $appName" 2
continue
}
$tmpApp = $tmpApps | Where displayVersion -eq $appVer
if(-not $tmpApp)
{
Write-Log "No $appName application found with version $appVer" 2
continue
}
elseif(-not ($tmpApp | measure).Count -gt 1)
{
Write-Log "Multiple $appName application found with version $appVer" 2
continue
}
Write-Log "Add $appName ($appVer) to Dependency list"
$releationShips.relationships += [PSCustomObject]@{
"@odata.type" = "#microsoft.graph.mobileAppDependency"
targetId = $tmpApp.Id
dependencyType = $appType
}
}
}
if($supAppsInfo)
{
foreach($suppApp in ($supAppsInfo -split "[|][*][|]"))
{
$appName, $appVer, $appId, $appType = $suppApp -split "[|][!][|]"
if(-not $appName -or -not $appVer)
{
Write-Log "Could not get Name and Version from string: $appApp" 2
continue
}
$tmpApps = (Invoke-GraphRequest -Url "/deviceAppManagement/mobileApps?`$filter=displayName eq '$appName'").value
if(-not $tmpApps)
{
Write-Log "No application found with name $appName" 2
continue
}
$tmpApp = $tmpApps | Where displayVersion -eq $appVer
if(-not $tmpApp)
{
Write-Log "No $appName application found with version $appVer" 2
continue
}
elseif(-not ($tmpApp | measure).Count -gt 1)
{
Write-Log "Multiple $appName application found with version $appVer" 2
continue
}
Write-Log "Add $appName ($appVer) to Supersedence list"
$releationShips.relationships += [PSCustomObject]@{
"@odata.type" = "#microsoft.graph.mobileAppSupersedence"
targetId = $tmpApp.Id
supersedenceType = $appType
}
}
}
if($releationShips.relationships.Count -gt 0)
{
$json = Update-JsonForEnvironment (ConvertTo-Json $releationShips -Depth 20)
Write-Log "Update app references"
Invoke-GraphRequest -Url "/deviceAppManagement/mobileApps/$($obj.Id)/updateRelationships" -Method "POST" -Body $json
}
}
}
@@ -3515,10 +3796,13 @@ function Start-PreImportADMXFiles
return
}
$bytes = [IO.File]::ReadAllBytes($admxFile)
#$bytes = [IO.File]::ReadAllBytes($admxFile)
$bytes = Get-ASCIIBytes ([IO.File]::ReadAllText($admxFile))
$obj.content = [Convert]::ToBase64String($bytes)
$bytes = [IO.File]::ReadAllBytes($admlFile)
#$bytes = [IO.File]::ReadAllBytes($admlFile)
$bytes = Get-ASCIIBytes ([IO.File]::ReadAllText($admlFile))
$obj.groupPolicyUploadedLanguageFiles += [PSCustomObject]@{
fileName = [io.path]::GetFileName($admlFile)
content = [Convert]::ToBase64String($bytes)

View File

@@ -10,7 +10,7 @@ This module manages Application objects in Intune e.g. uploading application fil
#>
function Get-ModuleVersion
{
'3.9.1'
'3.9.2'
}
#########################################################################################
@@ -94,26 +94,33 @@ function Copy-MSILOB
$tmpFile = [IO.Path]::GetTempFileName()
$msiInfo = Get-MSIFileInformation $msiFile @("ProductName", "ProductCode", "ProductVersion", "ProductLanguage")
$msiInfo = Get-MSIFileInformation $msiFile @("ProductName", "ProductCode", "ProductVersion", "ProductLanguage", "UpgradeCode", "ALLUSERS")
if(-not $msiInfo) { return }
$fileEncryptionInfo = New-IntuneEncryptedFile $msiFile $tmpFile
[xml]$manifestXML = '<MobileMsiData MsiExecutionContext="Any" MsiRequiresReboot="false" MsiUpgradeCode="" MsiIsMachineInstall="true" MsiIsUserInstall="false" MsiIncludesServices="false" MsiContainsSystemRegistryKeys="false" MsiContainsSystemFolders="false"></MobileMsiData>'
$manifestXML.MobileMsiData.MsiUpgradeCode = $msiInfo["ProductCode"]
$manifestXML.MobileMsiData.MsiUpgradeCode = $msiInfo["UpgradeCode"]
if($msiInfo["ALLUSERS"] -eq 1)
{
$manifestXML.MobileMsiData.MsiExecutionContext = "System"
}
$appFileBody = @{
"@odata.type" = "#microsoft.graph.mobileAppContentFile"
name = [IO.Path]::GetFileName($msiFile)
size = (Get-Item $msiFile).Length
sizeEncrypted = (Get-Item $tmpFile).Length
manifest = [Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($manifestXML.OuterXml))
isDependency = $false
}
Add-FileToIntuneApp $appId $appType $tmpFile $appFileBody
Remove-Item $tmpFile -Force
$fileEncryptionInfo
}
function Copy-iOSLOB
@@ -149,6 +156,8 @@ function Copy-iOSLOB
Add-FileToIntuneApp $appId $appType $tmpFile $appFileBody
Remove-Item $tmpFile -Force
$fileEncryptionInfo
}
function Copy-AndroidLOB
@@ -185,6 +194,8 @@ function Copy-AndroidLOB
Add-FileToIntuneApp $appId $appType $tmpFile $appFileBody
Remove-Item $tmpFile -Force
$fileEncryptionInfo
}
function Copy-Win32LOBPackage
@@ -235,7 +246,7 @@ function Copy-Win32LOBPackage
$fileBody = @{
"@odata.type" = "#microsoft.graph.mobileAppContentFile"
name = $DetectionXML.ApplicationInfo.FileName
name = "IntunePackage.intunewin"
size = [int64]$DetectionXML.ApplicationInfo.UnencryptedContentSize
sizeEncrypted = (Get-Item $tmpIntunewinFile).Length
manifest = $null
@@ -245,46 +256,59 @@ function Copy-Win32LOBPackage
Add-FileToIntuneApp $appId $appType $tmpIntunewinFile $fileBody
# Remove extracted inintunewin file
Remove-Item $tmpIntunewinPath -Force -Recurse
Remove-Item $tmpIntunewinPath -Force -Recurse
$fileEncryptionInfo
}
function Add-FileToIntuneApp
{
param($appId, $appType, $appFile, $fileBody)
$contentVersion = Invoke-GraphRequest -Url "/deviceAppManagement/mobileApps/$appId/$appType/contentVersions" -HttpMethod POST -Content "{}"
$contentVersion = Invoke-GraphRequest -Url "/deviceAppManagement/mobileApps/$appId/$appType/contentVersions" -HttpMethod POST -Content "{}" -ODataMetadata "Minimal"
$contentVersionId = $contentVersion.id
$fileObj = Invoke-GraphRequest -Url "/deviceAppManagement/mobileApps/$appId/$appType/contentVersions/$contentVersionId/files" -HttpMethod POST -Content (ConvertTo-Json $fileBody -Depth 5)
$fileObj = Invoke-GraphRequest -Url "/deviceAppManagement/mobileApps/$appId/$appType/contentVersions/$contentVersionId/files" -HttpMethod POST -Content (ConvertTo-Json $fileBody -Depth 5) -ODataMetadata "Minimal"
if(-not $fileObj)
{
return
}
Write-Log "File object created. ID: $($fileObj.id)"
# Wait for Azure storage URI
$fileObj = Wait-IntuneFileState "/deviceAppManagement/mobileApps/$appId/$appType/contentVersions/$contentVersionId/files/$($fileObj.Id)" "AzureStorageUriRequest"
if(-not $fileObj)
{
Write-Log "No File Object returned from commit. Upload failed" 3
return
}
# Upload file
Send-IntuneFileToAzureStorage $fileObj.azureStorageUri $appFile "/deviceAppManagement/mobileApps/$appId/$appType/contentVersions/$contentVersionId/files/$($fileObj.Id)"
Send-IntuneFileToAzureStorage $fileObj.azureStorageUri $appFile "/deviceAppManagement/mobileApps/$appId/$appType/contentVersions/$contentVersionId/files/$($fileObj.Id)" | Out-Null
# Commit the file
$reponse = Invoke-GraphRequest -Url "/deviceAppManagement/mobileApps/$appId/$appType/contentVersions/$contentVersionId/files/$($fileObj.Id)/commit" -HttpMethod POST -Content (ConvertTo-Json $fileEncryptionInfo -Depth 5)
Invoke-GraphRequest -Url "/deviceAppManagement/mobileApps/$appId/$appType/contentVersions/$contentVersionId/files/$($fileObj.Id)/commit" -HttpMethod POST -Content (ConvertTo-Json $fileEncryptionInfo -Depth 5) | Out-Null
Wait-IntuneFileState "/deviceAppManagement/mobileApps/$appId/$appType/contentVersions/$contentVersionId/files/$($fileObj.Id)" "CommitFile"
Wait-IntuneFileState "/deviceAppManagement/mobileApps/$appId/$appType/contentVersions/$contentVersionId/files/$($fileObj.Id)" "CommitFile" | Out-Null
$fiUpload = [IO.FileInfo]$appFile
# Commit the content version
$commitAppBody = @{
"@odata.type" = "#$appType"
committedContentVersion = $contentVersionId
fileName = $fiUpload.Name
}
$reponse = Invoke-GraphRequest -Url "/deviceAppManagement/mobileApps/$appId" -HttpMethod PATCH -Content (ConvertTo-Json $commitAppBody -Depth 5)
# if($fileBody.Name) {
# $fileUploadName = $fileBody.Name
# }
# else {
$fiUpload = [IO.FileInfo]$appFile
$fileUploadName = $fiUpload.Name
# }
$commitAppBody.Add("fileName",$fileUploadName)
Invoke-GraphRequest -Url "/deviceAppManagement/mobileApps/$appId" -HttpMethod PATCH -Content (ConvertTo-Json $commitAppBody -Depth 5) | Out-Null
Write-Log "Upload finished for file $fileUploadName version $contentVersionId"
}
function Wait-IntuneFileState
@@ -318,7 +342,7 @@ function Wait-IntuneFileState
return
}
Start-Sleep -s 5
Start-Sleep -Seconds 1
}
if($succes -eq $false)
@@ -635,4 +659,102 @@ function New-IntuneEncryptedFile
$fileEncryptionInfo.fileEncryptionInfo = $encryptionInfo
$fileEncryptionInfo
}
function Start-DecryptFile
{
param($sourceFile, $targetFile, $encryptionKey, $initializationVector)
if([IO.File]::Exists($targetFile))
{
$fi = [IO.FileInfo]$targetFile
$newName = $fi.Name + "_$((Get-Date).ToString("yyyyMMdd_HHmm"))" + $fi.Extension
$targetFile = $fi.DirectoryName + "\$newName"
Write-Log "Target file exists. Changing target file to $targetFile" 2
}
$bufferBlockSize = 1024 * 4
try
{
$aes = [System.Security.Cryptography.Aes]::Create()
$buffer = New-Object byte[] $bufferBlockSize
$bytesRead = 0
$targetStream = [System.IO.File]::Open($targetFile, [System.IO.FileMode]::Create, [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::None)
try
{
$sourceStream = [System.IO.File]::Open($sourceFile, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::None)
$decryptor = $aes.CreateDecryptor([Convert]::FromBase64String($encryptionKey), [Convert]::FromBase64String($initializationVector))
$decryptoStream = New-Object System.Security.Cryptography.CryptoStream -ArgumentList @($targetStream, $decryptor, [System.Security.Cryptography.CryptoStreamMode]::Write)
$sourceStream.Seek(48L, [System.IO.SeekOrigin]::Begin)
while (($bytesRead = $sourceStream.Read($buffer, 0, $bufferBlockSize)) -gt 0)
{
$decryptoStream.Write($buffer, 0, $bytesRead)
$decryptoStream.Flush()
}
$decryptoStream.FlushFinalBlock()
}
finally
{
if ($null -ne $decryptoStream) { $decryptoStream.Dispose() }
if ($null -ne $targetStream) { $targetStream.Dispose() }
if ($null -ne $decryptor) { $decryptor.Dispose() }
if ($null -ne $sourceStream) { $sourceStream.Dispose() }
}
}
finally
{
if ($null -ne $sourceStream) { $sourceStream.Dispose() }
if ($null -ne $aes) { $aes.Dispose() }
}
}
function Start-DownloadAppContent
{
param($obj, $destinationFile)
# Not use but kept for reference. File can be download but it will be encrypted
if([IO.File]::Exists($destinationFile))
{
try { [IO.File]::Delete($encryptionFile) }
catch {}
}
$appId = $obj.Id
$appInfo = Invoke-GraphRequest -Url "$($global:graphURL)/deviceAppManagement/mobileApps/$appId"
$appType = $appInfo.'@odata.type'.Trim('#')
#$contentVersions = Invoke-GraphRequest -Url "$($global:graphURL)/deviceAppManagement/mobileApps/$appId/$appType/contentVersions"
#$contentVerId = $contentVersions.Value[0].id
$contentVerId = $appInfo.committedContentVersion
$contentFiles = Invoke-GraphRequest "/deviceAppManagement/mobileApps/$appId/$appType/contentVersions/$contentVerId/files"
$contentFile = Invoke-GraphRequest -Url "/deviceAppManagement/mobileApps/$appId/$appType/contentVersions/$contentVerId/files/$($contentFiles.value[-1].Id)" -NoError
if(-not $contentFile)
{
foreach($file in $contentFiles.value)
{
if($contentFiles.value[-1].Id -eq $file.id) { continune }
# NOT happy about this. file objects are not always returned in the order of upload.
$contentFile = Invoke-GraphRequest -Url "/deviceAppManagement/mobileApps/$appId/$appType/contentVersions/$contentVerId/files/$($file.Id)" -NoError
if($contentFile)
{
break
}
}
}
Start-DownloadFile $contentFile.azureStorageUri $destinationFile
}

View File

@@ -10,7 +10,7 @@ This module manages Authentication for the application with MSAL. It is also res
#>
function Get-ModuleVersion
{
'3.9.1'
'3.9.2'
}
$global:msalAuthenticator = $null
@@ -158,6 +158,10 @@ function Clear-MSALCurentUserVaiables
{
$global:MSALTenantId = $null
$global:MSALGraphEnvironment = $null
$script:jwtAccessToken = $null
$script:jwtIdToken = $null
}
function Get-MSALCurrentApp
@@ -223,14 +227,23 @@ function Get-MSALUserInfo
if($global:MSALToken)
{
Write-Log "Get current user"
$tmpMe = MSGraph\Invoke-GraphRequest -Url "ME" -SkipAuthentication -ODataMetadata "Skip"
if($null -ne $tmpMe -and $tmpMe.creationType -ne "Invitation")
if($script:jwtAccessToken.Payload.idtyp -ne "app")
{
### Only get user info from home tenant
$global:Me = $tmpMe
Write-Log "Get profile picture"
$global:profilePhoto = "$($env:LOCALAPPDATA)\CloudAPIPowerShellManagement\$($global:Me.Id).jpeg"
MSGraph\Invoke-GraphRequest "me/photos/48x48/`$value" -OutFile $global:profilePhoto -SkipAuthentication -NoError | Out-Null
$tmpMe = MSGraph\Invoke-GraphRequest -Url "ME" -SkipAuthentication -ODataMetadata "Skip"
if($null -ne $tmpMe -and $tmpMe.creationType -ne "Invitation")
{
### Only get user info from home tenant
$global:Me = $tmpMe
Write-Log "Get profile picture"
$global:profilePhoto = "$($env:LOCALAPPDATA)\CloudAPIPowerShellManagement\$($global:Me.Id).jpeg"
MSGraph\Invoke-GraphRequest "me/photos/48x48/`$value" -OutFile $global:profilePhoto -SkipAuthentication -NoError | Out-Null
}
}
else
{
$global:profilePhoto = $null
$global:me = $script:jwtAccessToken.Payload.app_displayname
}
Write-Log "Get organization info"
@@ -834,6 +847,42 @@ function Connect-MSALUser
Write-LogDebug "Authenticate"
if($global:MainAppStarted -eq $false)
{
$script:AppLogin = (Get-SettingValue "GraphAzureAppLogin") -or ($global:TenantId -and $global:AzureAppId -and ($global:ClientSecret -or $global:ClientCert))
}
if($script:AppLogin)
{
if($global:MSALToken -and $global:MSALToken.ExpiresOn.LocalDateTime.Ticks -gt ((Get-Date).AddMinutes(-5)).Ticks)
{
return
}
# Get login info for silent job from settings
if(-not $global:AzureAppId) { $global:AzureAppId = Get-SettingValue "GraphAzureAppId" -TenantID $global:TenantId }
if(-not $global:ClientSecret -and -not $global:ClientCert) { $global:ClientSecret = Get-SettingValue "GraphAzureAppSecret" -TenantID $global:TenantId }
if(-not $global:ClientSecret -and -not $global:ClientCert) { $global:ClientCert = Get-SettingValue "GraphAzureAppCert" -TenantID $global:TenantId }
if($global:AzureAppId -and $global:ClientSecret -and $global:TenantId)
{
Connect-MSALClientApp $global:AzureAppId $global:TenantId -secret $global:ClientSecret
}
elseif($global:AzureAppId -and $global:ClientCert -and $global:TenantId)
{
Connect-MSALClientApp $global:AzureAppId $global:TenantId -certificate $global:ClientCert
}
else
{
Write-Log "Azure AppId, Tenant Id and Sercret/Cert must be specified for App logins" 3
}
Invoke-MSALAuthenticationUpdated $global:MSALToken
return
}
if($ShowMenu -eq $true -and ((Get-SettingValue "AzureADLoginMenu") -eq $true))
{
if((Show-MSALLoginMenu) -eq $false) { return }
@@ -1167,7 +1216,8 @@ function Connect-MSALUser
Save-Setting "" "LastLoggedOnUser" $authResult.Account.UserName
Save-Setting "" "LastLoggedOnUserId" $authResult.Account.HomeAccountId.ObjectId
}
Invoke-MSALAuthenticationUpdated $authResult
<#
Write-LogDebug "User, tenant or app has changed"
Get-MSALUserInfo
if($authResult)
@@ -1175,9 +1225,26 @@ function Connect-MSALUser
Invoke-MSALCheckObjectViewAccess $authResult
}
Invoke-ModuleFunction "Invoke-GraphAuthenticationUpdated"
#>
}
}
function local:Invoke-MSALAuthenticationUpdated
{
param($authResult)
Write-LogDebug "User, tenant or app has changed"
$script:jwtAccessToken = Get-JWTtoken $global:MSALToken.AccessToken
$script:jwtIdToken = Get-JWTtoken $global:MSALToken.IdToken
Get-MSALUserInfo
if($authResult)
{
Invoke-MSALCheckObjectViewAccess $authResult
}
Invoke-ModuleFunction "Invoke-GraphAuthenticationUpdated"
}
function Start-MSALConsentPrompt
{
param([switch]$PassThru, $authToken)
@@ -1254,6 +1321,22 @@ function Invoke-MSALCheckObjectViewAccess
Set-XamlProperty $script:userEllipsGrid "lnkRequestConsent" "Visibility" "Visible"
}
$accessToken = $null
if($authToken)
{
$accessToken = Get-JWTtoken $authToken.AccessToken
}
$curPermissions = $null
if($accessToken.Payload.idtyp -eq "app")
{
$curPermissions = $accessToken.Payload.roles
}
elseif($accessToken.Payload.scp)
{
$curPermissions = $accessToken.Payload.scp.Split(" ")
}
foreach($viewObjInfo in ($global:viewObjects | Where { $_.ViewInfo.AuthenticationID -eq "MSAL" }))
{
$viewObjInfo = $global:viewObjects | Where { $_.ViewInfo.Id -eq $global:EMViewObject.Id }
@@ -1262,10 +1345,8 @@ function Invoke-MSALCheckObjectViewAccess
{
if($authToken)
{
$accessToken = Get-JWTtoken $authToken.AccessToken
if($accessToken.Payload.scp)
if($curPermissions)
{
$curPermissions = $accessToken.Payload.scp.Split(" ")
foreach($viewItem in $viewObjInfo.ViewItems)
{
$full = 0
@@ -1400,7 +1481,7 @@ function Disconnect-MSALUser
$logout = $true
if(-not $global:MSALToken.Account) { return }
$user = $global:MSALToken.Account # Logout current user
$global:MSALToken = $null
$global:MSALToken = $null
Clear-MSALCurentUserVaiables # Only clear variables for current user
$msg = "Do you want to remove the token from the cache?"
$title = "Remove token?"
@@ -1563,6 +1644,10 @@ function Get-MSALProfileEllipse
{
$initials = "$($global:me.userPrincipalName[0])".ToUpper()
}
elseif($script:jwtAccessToken.Payload.idtyp -eq "app")
{
$initials = "APP"
}
$grd = Get-MSALUserPhotoEllips -size $size -fontSize $fontSize -Color $Color
@@ -1586,8 +1671,15 @@ function Get-MSALProfileEllipse
$global:grdProfileInfo.Tag = $grd
$grd.Tag = $global:grdProfileInfo
Set-XamlProperty $global:grdProfileInfo "txtOrganization" "Text" $global:Organization.displayName
Set-XamlProperty $global:grdProfileInfo "txtUsername" "Text" $global:me.displayName
Set-XamlProperty $global:grdProfileInfo "txtLogonName" "Text" $global:me.userPrincipalName
if($script:jwtAccessToken.Payload.idtyp -eq "app")
{
Set-XamlProperty $global:grdProfileInfo "txtUsername" "Text" "App Login"
}
else
{
Set-XamlProperty $global:grdProfileInfo "txtUsername" "Text" $global:me.displayName
Set-XamlProperty $global:grdProfileInfo "txtLogonName" "Text" $global:me.userPrincipalName
}
$global:tokenInfo = Get-JWTtoken $global:MSALToken.AccessToken
if($global:tokenInfo)
@@ -1606,11 +1698,16 @@ function Get-MSALProfileEllipse
$tmpObj.SetValue([System.Windows.Controls.Grid]::RowProperty,1)
$tmpObj.SetValue([System.Windows.Controls.Grid]::RowSpanProperty,2)
}
if($tmpObj)
{
$profileGrid.Children.Add($tmpObj) | Out-Null
}
if($script:jwtAccessToken.Payload.idtyp -eq "app")
{
$tmpObj.Visibility = "Collapsed"
}
$global:grdProfileInfo.Add_Loaded({param($obj, $e)
$point = $obj.Tag.TransformToAncestor($window).Transform([System.Windows.Point]::new(0,0));
@@ -1618,134 +1715,137 @@ function Get-MSALProfileEllipse
[System.Windows.Controls.Canvas]::SetTop($obj,($point.Y + $obj.Tag.ActualHeight))
})
#########################################################################################################
### Show / Hide consent button
#########################################################################################################
$script:userEllipsGrid = $tmpObj
if(($script:missingPermissions | measure).Count -eq 0)
if($script:jwtAccessToken.Payload.idtyp -ne "app")
{
Set-XamlProperty $script:userEllipsGrid "lnkRequestConsent" "Visibility" "Collapsed"
}
Add-XamlEvent $script:userEllipsGrid "lnkRequestConsent" "add_Click" {
Start-MSALConsentPrompt
}
$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 $accounts)
{
# Skip current logged on user
if($global:MSALToken.Account.Username -eq $Account.Username -or
$global:MSALToken.Account.HomeAccountId.ObjectId -eq $Account.HomeAccountId.ObjectId) { continue }
Add-CachedUser $account $otherLogins
}
#########################################################################################################
### Add login with another user
#########################################################################################################
$grdAccount = [System.Windows.Controls.Grid]::new()
$cd = [System.Windows.Controls.ColumnDefinition]::new()
$grdAccount.ColumnDefinitions.Add($cd)
$cd = [System.Windows.Controls.ColumnDefinition]::new()
$cd.Width = [double]::NaN
$grdAccount.ColumnDefinitions.Add($cd)
$icon = Get-XamlObject ($global:AppRootFolder + "\Xaml\Icons\Logon.xaml")
$icon.Width = 24
$icon.Height = 24
$icon.Margin = "0,0,5,0"
$grdAccount.Children.Add($icon) | Out-Null
$lbObj = [Windows.Markup.XamlReader]::Parse("<TextBlock $wpfNS>Sign in with a different account</TextBlock>")
$lbObj.SetValue([System.Windows.Controls.Grid]::ColumnProperty,1)
#$lbObj.Style = $window.TryFindResource("HoverUnderlineStyle")
$grdAccount.Children.Add($lbObj) | Out-Null
$lnkButton = [System.Windows.Controls.Button]::new()
$lnkButton.Content = $grdAccount
$lnkButton.Style = $window.TryFindResource("LinkButton")
$lnkButton.Margin = "0,5,0,0"
$lnkButton.Cursor = "Hand"
$lnkButton.Tag = $account
$lnkButton.add_Click({
Write-Status "Logging in..."
Hide-Popup
Connect-MSALUser -Interactive -ShowMenu
if($global:curObjectType)
#########################################################################################################
### Show / Hide consent button
#########################################################################################################
$script:userEllipsGrid = $tmpObj
if(($script:missingPermissions | measure).Count -eq 0)
{
Show-GraphObjects
Set-XamlProperty $script:userEllipsGrid "lnkRequestConsent" "Visibility" "Collapsed"
}
Write-Status ""
})
Add-XamlEvent $script:userEllipsGrid "lnkRequestConsent" "add_Click" {
Start-MSALConsentPrompt
}
$otherLogins = $global:grdProfileInfo.FindName("grdCachedAccounts")
$otherLogins = $global:grdProfileInfo.FindName("grdLoginAccount")
Add-GridObject $otherLogins $lnkButton
$otherLogins = $global:grdProfileInfo.FindName("grdTenantAccounts")
if(($script:AccessableTenants | measure).Count -gt 1)
{
#########################################################################################################
### Add switch to another tenant
### Add cached users
#########################################################################################################
$lbObj = [Windows.Markup.XamlReader]::Parse("<TextBlock $wpfNS><Bold>Tenants:</Bold></TextBlock>")
$lbObj.Margin = "0,5,0,0"
Add-GridObject $otherLogins $lbObj
foreach($tenant in $script:AccessableTenants)
if((Get-SettingValue "SortAccountList") -eq $true)
{
try
$accounts = $global:MSALAccounts | Sort -Property Username
}
else
{
$accounts = $global:MSALAccounts
}
foreach($account in $accounts)
{
# Skip current logged on user
if($global:MSALToken.Account.Username -eq $Account.Username -or
$global:MSALToken.Account.HomeAccountId.ObjectId -eq $Account.HomeAccountId.ObjectId) { continue }
Add-CachedUser $account $otherLogins
}
#########################################################################################################
### Add login with another user
#########################################################################################################
$grdAccount = [System.Windows.Controls.Grid]::new()
$cd = [System.Windows.Controls.ColumnDefinition]::new()
$grdAccount.ColumnDefinitions.Add($cd)
$cd = [System.Windows.Controls.ColumnDefinition]::new()
$cd.Width = [double]::NaN
$grdAccount.ColumnDefinitions.Add($cd)
$icon = Get-XamlObject ($global:AppRootFolder + "\Xaml\Icons\Logon.xaml")
$icon.Width = 24
$icon.Height = 24
$icon.Margin = "0,0,5,0"
$grdAccount.Children.Add($icon) | Out-Null
$lbObj = [Windows.Markup.XamlReader]::Parse("<TextBlock $wpfNS>Sign in with a different account</TextBlock>")
$lbObj.SetValue([System.Windows.Controls.Grid]::ColumnProperty,1)
#$lbObj.Style = $window.TryFindResource("HoverUnderlineStyle")
$grdAccount.Children.Add($lbObj) | Out-Null
$lnkButton = [System.Windows.Controls.Button]::new()
$lnkButton.Content = $grdAccount
$lnkButton.Style = $window.TryFindResource("LinkButton")
$lnkButton.Margin = "0,5,0,0"
$lnkButton.Cursor = "Hand"
$lnkButton.Tag = $account
$lnkButton.add_Click({
Write-Status "Logging in..."
Hide-Popup
Connect-MSALUser -Interactive -ShowMenu
if($global:curObjectType)
{
$lbObj = [Windows.Markup.XamlReader]::Parse("<TextBlock $wpfNS HorizontalAlignment=`"Stretch`"><Bold>$($tenant.DisplayName)</Bold><LineBreak/>$($tenant.defaultDomain)<LineBreak/>$($tenant.tenantId)</TextBlock>")
if($tenant.tenantId -ne $global:MSALToken.TenantId)
{
$lbObj.Style = $window.TryFindResource("HoverUnderlineStyleWithBackground")
$lbObj.HorizontalAlignment = "Stretch"
$lnkButton = [System.Windows.Controls.Button]::new()
$lnkButton.Content = $lbObj
$lnkButton.HorizontalAlignment = "Stretch"
$lnkButton.Style = $window.TryFindResource("ContentButton")
$lnkButton.Margin = "0,5,0,0"
$lnkButton.Cursor = "Hand"
$lnkButton.Tag = $tenant
$lnkButton.add_Click({
Write-Status "Logging in to $($this.Tag.DisplayName)"
# Set authority to selected tenant
$global:MSALTenantId = $this.Tag.tenantId
Hide-Popup
Connect-MSALUser -Account ($global:MSALAccounts | Where UserName -eq $global:MSALToken.Account.Username)
if($global:curObjectType)
{
Show-GraphObjects
}
Write-Status ""
})
Add-GridObject $otherLogins $lnkButton
}
else
{
$lbObj.Background = $window.TryFindResource("SelectedRowBackgroundColor")
$lbObj.Margin = "0,5,0,0"
Add-GridObject $otherLogins $lbObj
}
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)
{
#########################################################################################################
### Add switch to another tenant
#########################################################################################################
$lbObj = [Windows.Markup.XamlReader]::Parse("<TextBlock $wpfNS><Bold>Tenants:</Bold></TextBlock>")
$lbObj.Margin = "0,5,0,0"
Add-GridObject $otherLogins $lbObj
foreach($tenant in $script:AccessableTenants)
{
try
{
$lbObj = [Windows.Markup.XamlReader]::Parse("<TextBlock $wpfNS HorizontalAlignment=`"Stretch`"><Bold>$($tenant.DisplayName)</Bold><LineBreak/>$($tenant.defaultDomain)<LineBreak/>$($tenant.tenantId)</TextBlock>")
if($tenant.tenantId -ne $global:MSALToken.TenantId)
{
$lbObj.Style = $window.TryFindResource("HoverUnderlineStyleWithBackground")
$lbObj.HorizontalAlignment = "Stretch"
$lnkButton = [System.Windows.Controls.Button]::new()
$lnkButton.Content = $lbObj
$lnkButton.HorizontalAlignment = "Stretch"
$lnkButton.Style = $window.TryFindResource("ContentButton")
$lnkButton.Margin = "0,5,0,0"
$lnkButton.Cursor = "Hand"
$lnkButton.Tag = $tenant
$lnkButton.add_Click({
Write-Status "Logging in to $($this.Tag.DisplayName)"
# Set authority to selected tenant
$global:MSALTenantId = $this.Tag.tenantId
Hide-Popup
Connect-MSALUser -Account ($global:MSALAccounts | Where UserName -eq $global:MSALToken.Account.Username)
if($global:curObjectType)
{
Show-GraphObjects
}
Write-Status ""
})
Add-GridObject $otherLogins $lnkButton
}
else
{
$lbObj.Background = $window.TryFindResource("SelectedRowBackgroundColor")
$lbObj.Margin = "0,5,0,0"
Add-GridObject $otherLogins $lbObj
}
}
catch {}
}
catch {}
}
}
@@ -1807,7 +1907,12 @@ function Get-MSALProfileEllipse
{
Show-GraphObjects
}
}
}
if($script:jwtAccessToken.Payload.idtyp -eq "app")
{
Set-XamlProperty $tmpObj "lnkLogout" "Visibility" "Collapsed"
}
}
catch {
Write-LogError "Failed to create profile information object. Error: " $_.Exception
@@ -1983,12 +2088,21 @@ function Get-MSALMissingScopes
$script:missingPermissions = @()
if($script:jwtAccessToken.Payload.idtyp -eq "app")
{
$curScopes = $script:jwtAccessToken.Payload.roles
}
else
{
$curScopes = $authToken.Scopes
}
foreach($scope in $reqScopes)
{
$tmpScope = $scope.Split('/')[-1]
if($tmpScope -eq ".default") { continue }
if($authToken.Scopes -contains $tmpScope) { continue }
if(($authToken.Scopes -like "*/$tmpScope")) { continue }
if($curScopes -contains $tmpScope) { continue }
if(($curScopes -like "*/$tmpScope")) { continue }
$arrTemp = $tmpScope.Split(".")
if($arrTemp[1] -eq "Read")
{
@@ -2012,6 +2126,9 @@ function Show-MSALDecodedToken {
$tokenData,
$title
)
if(-not $tokenData.Header) { return }
$tokenArr = @()
foreach($prop in ($tokenData.Header | GM | Where MemberType -eq NoteProperty))
{

View File

@@ -10,7 +10,7 @@ This module manages Microsoft Grap fuctions like calling APIs, managing graph ob
#>
function Get-ModuleVersion
{
'3.9.1'
'3.9.2'
}
$global:MSGraphGlobalApps = @(
@@ -183,6 +183,14 @@ function Invoke-InitializeModule
Description = "Certificate for Azure App"
}) "GraphSilent"
Add-SettingsObject (New-Object PSObject -Property @{
Title = "Login with App in UI (Preview)"
Key = "GraphAzureAppLogin"
Type = "Boolean"
DefaultValue = $false
Description = "Login with specified app in the UI. Note: Change will require app restart"
}) "GraphSilent"
Add-SettingsObject (New-Object PSObject -Property @{
Title = "Refresh Objects after copy"
Key = "RefreshObjectsAfterCopy"
@@ -214,6 +222,15 @@ function Invoke-InitializeModule
DefaultValue = $false
Description = "Expand assignments when listing objects. This can be used in custom columns based on assignment info"
}) "GraphGeneral"
Add-SettingsObject (New-Object PSObject -Property @{
Title = "Use Graph 1.0 (Not Recommended)"
Key = "UseGraphV1"
Type = "Boolean"
DefaultValue = $false
Description = "This will use production verionof graph, v1.0. Note: Thot officially supported since this can have unpredicted results. Some parts will require Beta version of Graph."
}) "GraphGeneral"
}
function Get-GraphAppInfo
@@ -270,7 +287,7 @@ function Invoke-SettingsUpdated
function Initialize-GraphSettings
{
$script:defaultVersion = ""
}
function Invoke-GraphRequest
@@ -297,7 +314,7 @@ function Invoke-GraphRequest
$ODataMetadata = "full", # full, minimal, none or skip
[ValidateSet("beta","v1.0")]
$GraphVersion = "beta",
$GraphVersion = "",
[switch]
$AllPages,
@@ -317,6 +334,22 @@ function Invoke-GraphRequest
Connect-MSALUser
}
if(-not $GraphVersion)
{
if(-not $script:defaultVersion)
{
if((Get-SettingValue "UseGraphV1") -eq $true)
{
$script:defaultVersion = "v1.0"
}
else
{
$script:defaultVersion = "beta"
}
}
$GraphVersion = $script:defaultVersion
}
$params = @{}
$requestId = [Guid]::NewGuid().guid
@@ -1684,6 +1717,7 @@ function Show-GraphImportForm
$importedObjectsCurType = 0
$navigationPropObjects = @()
$arrImportedObjects = @()
foreach ($fileObj in $filesToImport)
{
if($allowUpdate -and $global:cbImportType.SelectedValue -ne "alwaysImport" -and (Reset-GraphObject $fileObj $global:dgObjects.ItemsSource))
@@ -1699,9 +1733,15 @@ function Show-GraphImportForm
ImportedObject = $importedObj
}
}
$arrImportedObjects += $importedObj
$importedObjectsCurType++
}
if($global:curObjectType.PostFilesImportCommand)
{
& $global:curObjectType.PostFilesImportCommand $global:curObjectType $arrImportedObjects $filesToImport
}
if($importedObjectsCurType -gt 0 -and $global:LoadedDependencyObjects -is [HashTable] -and $global:LoadedDependencyObjects.ContainsKey($global:curObjectType.Id))
{
Write-Log "Remove $($global:curObjectType.Title) from dependency cache"
@@ -1870,7 +1910,6 @@ function Show-GraphBulkImportForm
function Start-GraphObjectImport
{
Write-Status "Import objects" -Block
Write-Log "****************************************************************"
Write-Log "Start bulk import"
@@ -1920,6 +1959,8 @@ function Start-GraphObjectImport
$importedObjectsCurType = 0
$arrImportedObjects = @()
foreach ($fileObj in @($filesToImport))
{
$objName = Get-GraphObjectName $fileObj.Object $item.ObjectType
@@ -1943,11 +1984,17 @@ function Start-GraphObjectImport
ImportedObject = $importedObj
}
}
$arrImportedObjects = $importedObj
$importedObjects++
$importedObjectsCurType++
}
if($item.ObjectType.PostFilesImportCommand)
{
& $item.ObjectType.PostFilesImportCommand $item.ObjectType $arrImportedObjects $filesToImport
}
if($importedObjectsCurType -gt 0 -and $global:LoadedDependencyObjects -is [HashTable] -and $global:LoadedDependencyObjects.ContainsKey($item.ObjectType.Id))
{
Write-Log "Remove $($item.ObjectType.Title) from dependency cache"
@@ -2243,6 +2290,11 @@ function Import-GraphFile
Import-GraphObjectAssignment $newObj $file.ObjectType $objClone.Assignments $file.FileInfo.FullName | Out-Null
}
if($newObj)
{
$file | Add-Member -NotePropertyName "ImportedObject" -NotePropertyValue $newObj
}
if($PassThru -eq $true -and $newObj)
{
$newObj