Add headless macOS CLI workflow

This commit is contained in:
2026-04-08 15:18:32 +02:00
parent faffa95d8a
commit 8fe71c0078
12 changed files with 917 additions and 66 deletions

View File

@@ -105,9 +105,12 @@ function Invoke-InitializeModule
Write-Log "Microsoft Intune PowerShell is being decomissioned. Please change to a supported app eg Microsoft Graph or a custom app!" 2
}
$viewPanel = Get-XamlObject ($global:AppRootFolder + "\Xaml\EndpointManagerPanel.xaml") -AddVariables
Set-EMViewPanel $viewPanel
$viewPanel = $null
if($global:hideUI -ne $true)
{
$viewPanel = Get-XamlObject (Join-Path $global:AppRootFolder "Xaml/EndpointManagerPanel.xaml") -AddVariables
Set-EMViewPanel $viewPanel
}
#Add menu group and items
$global:EMViewObject = (New-Object PSObject -Property @{
@@ -4417,4 +4420,4 @@ function Start-PreImportCommandAuthenticationContext
#endregion
Export-ModuleMember -alias * -function *
Export-ModuleMember -alias * -function *

View File

@@ -138,8 +138,8 @@ function Invoke-InitializeModule
}) "MSAL"
$script:MSALUseWAM = Get-SettingValue "UseWAM"
if($script:MSALUseWAM -and $PSVersionTable.PSVersion.Major -lt 7) {
Write-Log "WAM is only supported in PowerShell 7 and later. Disabling WAM" 2
if($script:MSALUseWAM -and ($PSVersionTable.PSVersion.Major -lt 7 -or -not (Test-IsWindowsPlatform))) {
Write-Log "WAM is only supported on Windows with PowerShell 7 and later. Disabling WAM" 2
$script:MSALUseWAM = $false
}
@@ -268,7 +268,7 @@ function Get-MSALUserInfo
### Only get user info from home tenant
$global:Me = $tmpMe
Write-Log "Get profile picture"
$global:profilePhoto = "$($env:LOCALAPPDATA)\CloudAPIPowerShellManagement\$($global:Me.Id).jpeg"
$global:profilePhoto = Join-Path (Get-CloudApiDataFolder) "$($global:Me.Id).jpeg"
MSGraph\Invoke-GraphRequest "me/photos/48x48/`$value" -OutFile $global:profilePhoto -SkipAuthentication -NoError | Out-Null
}
}
@@ -517,17 +517,17 @@ function Add-MSALPrereq
$DLLFiles = @()
if($PSVersionTable.PSVersion.Major -ge 7) {
$DLLFiles += [IO.FileInfo]($ScriptRoot + "\Bin\Microsoft.IdentityModel.Abstractions.dll")
$DLLFiles += [IO.FileInfo](Join-Path $ScriptRoot "Bin/Microsoft.IdentityModel.Abstractions.dll")
}
else {
$DLLFiles += [IO.FileInfo]($ScriptRoot + "\Bin\6.35.0\Microsoft.IdentityModel.Abstractions.dll")
$DLLFiles += [IO.FileInfo](Join-Path $ScriptRoot "Bin/6.35.0/Microsoft.IdentityModel.Abstractions.dll")
}
$DLLFiles += [IO.FileInfo]($ScriptRoot + "\Bin\Microsoft.Identity.Client.dll")
$DLLFiles += [IO.FileInfo](Join-Path $ScriptRoot "Bin/Microsoft.Identity.Client.dll")
if($script:MSALUseWAM) {
$DLLFiles += [IO.FileInfo]($ScriptRoot + "\BIN\$MSALDLLPath\Microsoft.Identity.Client.Extensions.Msal.dll")
$DLLFiles += [IO.FileInfo]($ScriptRoot + "\BIN\$MSALDLLPath\Microsoft.Identity.Client.Broker.dll")
$DLLFiles += [IO.FileInfo]($ScriptRoot + "\BIN\$MSALDLLPath\Microsoft.Identity.Client.Desktop.dll")
$DLLFiles += [IO.FileInfo]($ScriptRoot + "\BIN\$MSALDLLPath\Microsoft.Identity.Client.NativeInterop.dll")
$DLLFiles += [IO.FileInfo](Join-Path $ScriptRoot "Bin/$MSALDLLPath/Microsoft.Identity.Client.Extensions.Msal.dll")
$DLLFiles += [IO.FileInfo](Join-Path $ScriptRoot "Bin/$MSALDLLPath/Microsoft.Identity.Client.Broker.dll")
$DLLFiles += [IO.FileInfo](Join-Path $ScriptRoot "Bin/$MSALDLLPath/Microsoft.Identity.Client.Desktop.dll")
$DLLFiles += [IO.FileInfo](Join-Path $ScriptRoot "Bin/$MSALDLLPath/Microsoft.Identity.Client.NativeInterop.dll")
}
$DLLFiles | ForEach-Object {
@@ -570,7 +570,7 @@ function Add-MSALPrereq
try
{
Add-Type -Path ($ScriptRoot + "\CS\TokenCacheHelperEx.cs") -ReferencedAssemblies $RequiredAssemblies -IgnoreWarnings
Add-Type -Path (Join-Path $ScriptRoot "CS/TokenCacheHelperEx.cs") -ReferencedAssemblies $RequiredAssemblies -IgnoreWarnings
}
catch
{
@@ -809,7 +809,7 @@ function Get-MsalAuthenticationToken
{
# Login hung on rare occations
# Workaround: Added DoEvents
[System.Windows.Forms.Application]::DoEvents()
Invoke-AppDoEvents
Start-Sleep -Seconds 1
}
}
@@ -954,7 +954,7 @@ function Get-MSALApp
if($global:SkipTokenCacheHelperEx -ne $true -and (Get-SettingValue "CacheMSALToken"))
{
[TokenCacheHelperEx]::EnableSerialization($msalApp.UserTokenCache, "%LOCALAPPDATA%\CloudAPIPowerShellManagement\msalcahce.bin3")
[TokenCacheHelperEx]::EnableSerialization($msalApp.UserTokenCache, (Join-Path (Get-CloudApiDataFolder) "msalcahce.bin3"))
}
$script:MSALAllApps += $msalApp
}
@@ -1350,7 +1350,7 @@ function Connect-MSALUser
if((Get-SettingValue "CacheMSALToken"))
{
[TokenCacheHelperEx]::EnableSerialization($app.UserTokenCache, "%LOCALAPPDATA%\CloudAPIPowerShellManagement\msalcahce.bin3")
[TokenCacheHelperEx]::EnableSerialization($app.UserTokenCache, (Join-Path (Get-CloudApiDataFolder) "msalcahce.bin3"))
}
### Silent login
@@ -2377,4 +2377,4 @@ function Show-MSALDecodedToken {
Show-ModalForm $title $dg
}
Export-ModuleMember -alias * -function *
Export-ModuleMember -alias * -function *

View File

@@ -782,7 +782,7 @@ function Add-GraphObjectProperties
if($objects.Count -gt 0 -and $SortProperty -and ($objects[0] | GM -MemberType NoteProperty -Name $SortProperty))
{
$objects = $objects | sort -Property $SortProperty
$objects = $objects | Sort-Object -Property $SortProperty
}
$objects
@@ -1400,12 +1400,77 @@ function Invoke-SilentBatchJob
}
}
function New-GraphSilentBatchForm
{
param($Controls)
$form = New-HeadlessForm $Controls
foreach($control in $Controls)
{
New-Variable -Name $control.Name -Value $control -Force -Scope Global
}
$form
}
function New-GraphSilentExportForm
{
$controls = @(
(New-HeadlessControl -Name "txtExportPath" -Type "TextBox"),
(New-HeadlessControl -Name "txtExportNameFilter" -Type "TextBox"),
(New-HeadlessControl -Name "chkAddObjectType" -Type "CheckBox"),
(New-HeadlessControl -Name "chkExportAssignments" -Type "CheckBox"),
(New-HeadlessControl -Name "chkAddCompanyName" -Type "CheckBox"),
(New-HeadlessControl -Name "dgObjectsToExport" -Type "DataGrid")
)
$form = New-GraphSilentBatchForm $controls
Set-XamlProperty $form "txtExportPath" "Text" (?? (Get-Setting "" "LastUsedRoot") (Get-SettingValue "RootFolder"))
Set-XamlProperty $form "chkAddObjectType" "IsChecked" $true
Set-XamlProperty $form "chkExportAssignments" "IsChecked" (Get-SettingValue "ExportAssignments")
Set-XamlProperty $form "chkAddCompanyName" "IsChecked" (Get-SettingValue "AddCompanyName")
$form
}
function New-GraphSilentImportForm
{
$path = Get-Setting "" "LastUsedFullPath"
if($path)
{
$path = [IO.Directory]::GetParent($path).FullName
}
$controls = @(
(New-HeadlessControl -Name "txtImportPath" -Type "TextBox"),
(New-HeadlessControl -Name "txtImportNameFilter" -Type "TextBox"),
(New-HeadlessControl -Name "lblMigrationTableInfo" -Type "Label"),
(New-HeadlessControl -Name "chkAddObjectType" -Type "CheckBox"),
(New-HeadlessControl -Name "chkImportScopes" -Type "CheckBox"),
(New-HeadlessControl -Name "chkImportAssignments" -Type "CheckBox"),
(New-HeadlessControl -Name "chkReplaceDependencyIDs" -Type "CheckBox"),
(New-HeadlessControl -Name "cbImportType" -Type "ComboBox"),
(New-HeadlessControl -Name "dgObjectsToImport" -Type "DataGrid")
)
$form = New-GraphSilentBatchForm $controls
Set-XamlProperty $form "txtImportPath" "Text" (?? $path (Get-SettingValue "RootFolder"))
Set-XamlProperty $form "chkAddObjectType" "IsChecked" $true
Set-XamlProperty $form "chkImportAssignments" "IsChecked" (Get-SettingValue "ImportAssignments")
Set-XamlProperty $form "chkImportScopes" "IsChecked" (Get-SettingValue "ImportScopeTags")
Set-XamlProperty $form "chkReplaceDependencyIDs" "IsChecked" $true
Set-XamlProperty $form "cbImportType" "ItemsSource" $script:lstImportTypes
Set-XamlProperty $form "cbImportType" "SelectedValue" (Get-SettingValue "ImportType" "alwaysImport")
$form
}
function Start-GraphSilentBulkExport
{
param($settingsObj)
$script:exportForm = Get-XamlObject ($global:AppRootFolder + "\Xaml\BulkExportForm.xaml") -AddVariables
if(-not $script:exportForm) { return }
$script:exportForm = New-GraphSilentExportForm
$script:exportObjects = Get-GraphBatchObjectTypes $settingsObj.BulkExport
@@ -1414,8 +1479,6 @@ function Start-GraphSilentBulkExport
if(-not $viewObj.Title) { continue }
if($viewObj.ObjectType.ShowButtons -is [Object[]] -and $viewObj.ObjectType.ShowButtons -notcontains "Export") { continue }
Add-GraphExportExtensions $script:exportForm 0 $viewObj.ObjectType
}
Set-BatchProperties $settingsObj.BulkExport $script:exportForm
@@ -1449,8 +1512,7 @@ function Start-GraphSilentBulkImport
{
param($settingsObj)
$script:importForm = Get-XamlObject ($global:AppRootFolder + "\Xaml\BulkImportForm.xaml") -AddVariables
if(-not $script:importForm) { return }
$script:importForm = New-GraphSilentImportForm
# Get all objects but not selected
# This will allow dependencies
@@ -1479,11 +1541,10 @@ function Start-GraphSilentBulkImport
if(-not $viewObj.Title) { continue }
if($viewObj.ObjectType.ShowButtons -is [Object[]] -and $viewObj.ObjectType.ShowButtons -notcontains "Import") { continue }
Add-GraphImportExtensions $script:importForm 0 $viewObj.ObjectType
}
Set-BatchProperties $settingsObj.BulkImport $script:importForm
Set-XamlProperty $script:importForm "lblMigrationTableInfo" "Content" (Get-MigrationTableInfo)
$global:dgObjectsToImport.ItemsSource = @($script:importObjects)
@@ -2358,7 +2419,7 @@ function Get-GraphFileObjects
}
$fileArr = @()
foreach($file in (Get-Item -path "$path\*.json" @params))
foreach($file in (Get-Item -path (Join-Path $path "*.json") @params))
{
if($ObjectType.LoadObject)
{
@@ -2864,7 +2925,7 @@ function Add-GroupMigrationObject
# Export group info to json file for possible import
$grouspPath = Join-Path $path "Groups"
if(-not (Test-Path $grouspPath)) { mkdir -Path $grouspPath -Force -ErrorAction SilentlyContinue | Out-Null }
$fileName = "$grouspPath\$((Remove-InvalidFileNameChars $groupObj.displayName)).json"
$fileName = Join-Path $grouspPath "$((Remove-InvalidFileNameChars $groupObj.displayName)).json"
Save-GraphObjectToFile $groupObj $fileName
}
}
@@ -2907,7 +2968,7 @@ function Add-GraphMigrationObject
# Export group info to json file for possible import
$grouspPath = Join-Path $path "Groups"
if(-not (Test-Path $grouspPath)) { mkdir -Path $grouspPath -Force -ErrorAction SilentlyContinue | Out-Null }
$fileName = "$grouspPath\$((Remove-InvalidFileNameChars $graphObj.displayName)).json"
$fileName = Join-Path $grouspPath "$((Remove-InvalidFileNameChars $graphObj.displayName)).json"
Save-GraphObjectToFile $graphObj $fileName
}
}
@@ -3050,7 +3111,7 @@ function Get-GraphMigrationObjectsFromFile
if($global:GraphMigrationTable)
{
$fi = [IO.FileInfo]$global:GraphMigrationTable
$groupFi = [IO.FileInfo]($fi.DirectoryName + "\Groups\$((Remove-InvalidFileNameChars $migTableGroupName)).json")
$groupFi = [IO.FileInfo](Join-Path (Join-Path $fi.DirectoryName "Groups") "$((Remove-InvalidFileNameChars $migTableGroupName)).json")
}
if($groupFi.Exists -eq $true)
@@ -3197,13 +3258,13 @@ function Add-GraphDependencyObjects
continue
}
if([IO.Directory]::Exists(($importPath + "\" + $dep)))
if([IO.Directory]::Exists((Join-Path $importPath $dep)))
{
$path = ($importPath + "\" + $dep)
$path = (Join-Path $importPath $dep)
}
elseif([IO.Directory]::Exists(($parentPath + "\" + $dep)))
elseif([IO.Directory]::Exists((Join-Path $parentPath $dep)))
{
$path = ($parentPath + "\" + $dep)
$path = (Join-Path $parentPath $dep)
}
else
{
@@ -3674,7 +3735,7 @@ function Invoke-GraphBatchRequest
$retryAfter = 0
$tmpResults = Invoke-GraphRequest -Url "`$batch" -Body $json -Method "POST"
foreach($batchResult in ($tmpResults.responses | Sort -Property Id))
foreach($batchResult in ($tmpResults.responses | Sort-Object -Property Id))
{
if($batchResult.Status -ge 300 -or -not $batchResult.body)
{
@@ -4151,7 +4212,7 @@ function Show-GraphObjectInfo
if($prop.Name.Contains('@') -or $prop.Name.Contains('#')) { continue }
$objProps += ([PSCustomObject]@{ Name=$prop.Name;Value=$prop })
}
$objProps = $objProps | sort -Property Name
$objProps = $objProps | Sort-Object -Property Name
Set-XamlProperty $script:detailsForm "lstObjectProperties" "ItemsSource" $objProps
Add-XamlEvent $script:detailsForm "btnObjectColumnsReset" "Add_Click" -scriptBlock ([scriptblock]{
@@ -4633,4 +4694,4 @@ function Confirm-GraphMatchFilter
}
}
return $true
}
}