UGDSB.ApplicationFactory.psm1
#Region '.\Private\Add-AppFactoryAppEXE.ps1' 0 function Add-AppFactoryAppEXE{ [cmdletbinding()] [OutputType([System.Collections.Generic.List[String[]]])] param( [Parameter()][String]$directory, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][String]$AppSetupFileName, [Parameter()][string]$argumentList, [Parameter()][bool]$secureArgumentList, [Parameter()][int[]]$SuccessExitCodes, [Parameter()][int[]]$rebootExitCodes, [Parameter()][int[]]$ignoreExitCodes, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) $ApplicationScriptLines = [System.Collections.Generic.List[String[]]]@() # Set the Path that we should be working with if($directory -ne ""){ $executePath = "`"`$($($directory))\`$(`$AppSetupFileName)`"" } else{ $executePath = "`"`$(`$AppSetupFileName)`"" } $execute = "Start-ADTProcess -FilePath $($executePath) -ArgumentList `"`$(`$argumentList)`"" if ($PSBoundParameters.ContainsKey("secureArgumentList") -and $secureArgumentList) {$execute = "$($execute) -secureArgumentList"} if ($PSBoundParameters.ContainsKey("SuccessExitCodes") -and $SuccessExitCodes) {$execute = "$($execute) -SuccessExitCodes $($SuccessExitCodes -join ",")"} if ($PSBoundParameters.ContainsKey("rebootExitCodes") -and $rebootExitCodes) {$execute = "$($execute) -rebootExitCodes $($rebootExitCodes -join ",")"} if ($PSBoundParameters.ContainsKey("ignoreExitCodes") -and $ignoreExitCodes) {$execute = "$($execute) -ignoreExitCodes $($ignoreExitCodes -join ",")"} $ApplicationScriptLines.Add("`t`$AppSetupFileName = `"$($AppSetupFileName)`"") | Out-Null $ApplicationScriptLines.Add("`t`$argumentList = `"$($argumentList)`"") | Out-Null $ApplicationScriptLines.Add("`t$($execute)") | Out-Null return @(,$ApplicationScriptLines) } #EndRegion '.\Private\Add-AppFactoryAppEXE.ps1' 32 #Region '.\Private\Add-AppFactoryApplicationBlockingProcess.ps1' 0 function Add-AppFactoryApplicationBlockingProcess{ [cmdletbinding()] [OutputType([System.Collections.Generic.List[String[]]])] param( [Parameter()][switch]$interactive, [Parameter()][ValidateNotNullOrEmpty()][string[]]$blockingProcess, [Parameter()][ValidateNotNullOrEmpty()][int]$deferCount = 0, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) $ApplicationScriptLines = [System.Collections.Generic.List[String[]]]@() if($interactive.IsPresent){ $ApplicationScriptLines.Add("`t`$processExist = `$false") | Out-Null foreach ($item in $blockingProcess) { $ApplicationScriptLines.Add("`tif(Get-Process -Name `"$($item)`" -ErrorAction SilentlyContinue){`$processExist = `$true}") | Out-Null } $ApplicationScriptLines.Add("`tif (`$adtSession.IsProcessUserInteractive -and `$processExist) {") | Out-Null $ApplicationScriptLines.Add("`t`t`$params = @{") | Out-Null $ApplicationScriptLines.Add("`t`t`t`"CloseProcesses`" = '$($blockingProcess -join "','")'") | Out-Null $ApplicationScriptLines.Add("`t`t`t`"PersistPrompt`" = `$true") | Out-Null if ($deferCount -gt 0) { $ApplicationScriptLines.Add("`t`t`t`"AllowDefer`" = `$true") | Out-Null $ApplicationScriptLines.Add("`t`t`t`"DeferTimes`" = $($deferCount)") | Out-Null } $ApplicationScriptLines.Add("`t`t}") | Out-Null $ApplicationScriptLines.Add("`t`tShow-ADTInstallationWelcome @params") | Out-Null $ApplicationScriptLines.Add("`t}") | Out-Null $ApplicationScriptLines.Add("`telse {") | Out-Null foreach ($item in $blockingProcess) { $ApplicationScriptLines.Add("`t`t`Get-Process -Name `"$($item)`" -ErrorAction SilentlyContinue | Stop-Process -Force") | Out-Null } $ApplicationScriptLines.Add("`t}") | Out-Null } else{ foreach($item in $blockingProcess){ $ApplicationScriptLines.Add("`tGet-Process -Name `"$($item)`" -ErrorAction SilentlyContinue | Stop-Process -Force") | Out-Null } } return @(,$ApplicationScriptLines) } #EndRegion '.\Private\Add-AppFactoryApplicationBlockingProcess.ps1' 40 #Region '.\Private\Add-AppFactoryAppMSI.ps1' 0 function Add-AppFactoryAppMSI{ [cmdletbinding()] [OutputType([System.Collections.Generic.List[String[]]])] param( [Parameter()][String]$directory, [Parameter(Mandatory = $true, ParameterSetName = "AppSetupFileName")][ValidateNotNullOrEmpty()][String]$AppSetupFileName, [Parameter(Mandatory = $true, ParameterSetName = "productcode")][ValidateNotNullOrEmpty()][String]$productcode, [Parameter()][ValidateSet("Install", "Uninstall")][string]$Action = "Install", [Parameter()][string]$argumentList, [Parameter()][string]$additionalArgumentList, [Parameter()][bool]$secureArgumentList, [Parameter()][bool]$SkipMSIAlreadyInstalledCheck, [Parameter()][string]$Transforms, [Parameter()][int[]]$SuccessExitCodes, [Parameter()][int[]]$rebootExitCodes, [Parameter()][int[]]$ignoreExitCodes, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) $ApplicationScriptLines = [System.Collections.Generic.List[String[]]]@() if($PSBoundParameters.ContainsKey("AppSetupFileName") -and $AppSetupFileName){ if($directory -ne ""){ $executePath = "`"`$($($directory))\`$(`$AppSetupFileName)`"" } else{ $executePath = "`"`$(`$AppSetupFileName)`"" } $execute = "Start-ADTMsiProcess -Action `"$($Action)`" -FilePath $($executePath)" $ApplicationScriptLines.Add("`t`$AppSetupFileName = `"$($AppSetupFileName)`"") | Out-Null } else{ $execute = "Start-ADTMsiProcess -Action `"$($Action)`" -productcode `"$($productcode)`"" } if ($PSBoundParameters.ContainsKey("Transforms") -and $Transforms) { $ApplicationScriptLines.Add("`t`$Transforms = `"$($Transforms)`"") | Out-Null $execute = "$($execute) -Transforms `"`$($($directory))\`$(`$Transforms)`"" } if ($PSBoundParameters.ContainsKey("additionalArgumentList") -and $additionalArgumentList) { $ApplicationScriptLines.Add("`t`$additionalArgumentList = `"$($additionalArgumentList)`"") | Out-Null $execute = "$($execute) -AdditionalArgumentList `$additionalArgumentList" } if ($PSBoundParameters.ContainsKey("argumentList") -and $argumentList) { $ApplicationScriptLines.Add("`t`$argumentList = `"$($argumentList)`"") | Out-Null $execute = "$($execute) -argumentList `$argumentList" } if ($PSBoundParameters.ContainsKey("secureArgumentList") -and $secureArgumentList) {$execute = "$($execute) -secureArgumentList"} if ($PSBoundParameters.ContainsKey("SkipMSIAlreadyInstalledCheck") -and $SkipMSIAlreadyInstalledCheck) {$execute = "$($execute) -SkipMSIAlreadyInstalledCheck"} if ($PSBoundParameters.ContainsKey("SuccessExitCodes") -and $SuccessExitCodes) {$execute = "$($execute) -SuccessExitCodes $($SuccessExitCodes -join ",")"} if ($PSBoundParameters.ContainsKey("rebootExitCodes") -and $rebootExitCodes) {$execute = "$($execute) -rebootExitCodes $($rebootExitCodes -join ",")"} if ($PSBoundParameters.ContainsKey("ignoreExitCodes") -and $ignoreExitCodes) {$execute = "$($execute) -ignoreExitCodes $($ignoreExitCodes -join ",")"} $ApplicationScriptLines.Add("`t$($execute)") | Out-Null return @(,$ApplicationScriptLines) } #EndRegion '.\Private\Add-AppFactoryAppMSI.ps1' 53 #Region '.\Private\Add-AppFactoryAppWIM.ps1' 0 function Add-AppFactoryAppWIM{ [cmdletbinding()] [OutputType([System.Collections.Generic.List[String[]]])] param( [Parameter(Mandatory = $true)][ValidateSet("start","end")][string]$section, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$MountPath, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) $ApplicationScriptLines = [System.Collections.Generic.List[String[]]]@() # If this to mount the WIM add the following lines if($section -eq "start"){ $ApplicationScriptLines.Add("`t`$mountPath = `"$($MountPath)`"") | Out-Null $ApplicationScriptLines.Add("`t`$wimFile = Get-Childitem -Path `"`$(`$adtSession.dirFiles)`" -Filter `"*.wim`"") | Out-Null $ApplicationScriptLines.Add("`t`$wimPath = Join-Path `$adtSession.dirFiles -ChildPath `$wimFile") | Out-Null $ApplicationScriptLines.Add("`tMount-ADTWimFile -ImagePath `$wimPath -Path `$mountPath -Index 1") | Out-Null } else{ $ApplicationScriptLines.Add("`tDismount-ADTWimFile -Path `"$($MountPath)`"") | Out-Null } return @(,$ApplicationScriptLines) } #EndRegion '.\Private\Add-AppFactoryAppWIM.ps1' 22 #Region '.\Private\Connect-AppFactoryAzureStorage.ps1' 0 function Connect-AppFactoryAzureStorage { [CmdletBinding()] [OutputType([System.Collections.Generic.List[PSCustomObject]])] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$storageContainer, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][securestring]$storageSecret, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) begin { # Generate variables to connect to azure storage $storageVars = @{ "StorageAccountName" = $storageContainer "StorageAccountKey" = ConvertFrom-SecureString $storageSecret -AsPlainText } } process { try { if ($script:AppFactoryLogging) { Write-PSFMessage -Message "Creating Azure Storage Context for <c='green'>$($storageContainer)</c>" -Level $LogLevel -Tag "Storage", "$($storageContainer)" -Target "Application Factory Service" } $storageAccountContext = New-AzStorageContext @storageVars } catch { Write-PSFMessage -Message "Error Encountered: $($_)" -Level "Error" -Tag "Storage" -Target "Application Factory Service" throw $_ } } end { return $storageAccountContext } } #EndRegion '.\Private\Connect-AppFactoryAzureStorage.ps1' 33 #Region '.\Private\Get-AppFactoryAzureStorageAppItem.ps1' 0 <# .DESCRIPTION This cmdlet is designed to download contacts from Azure Storage Account .PARAMETER application The application object that we are working for so that we can ensure that get the correct and current data .PARAMETER LogLevel If logging is enabled, what level of logging do we want, default is verbose. #> function Get-AppFactoryAzureStorageAppItem { [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][PSCustomObject]$application, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) try { if ($script:AppFactoryLogging) { Write-PSFMessage -Message "[<c='green'>$($application.Information.DisplayName)</c>] Getting Azure Storage based application" -Level $LogLevel -Tag "Application", "$($application.Information.DisplayName)", "AzureStorage" -Target "Application Factory Service" } $StorageBlobContents = Get-AzStorageBlob -Container $application.SourceFiles.StorageAccountContainerName -Context $script:appStorageContext -ErrorAction Stop | Where-Object {$_.Name -ne "latest.json"} | Sort-Object LastModified -Descending $fileInfo = $StorageBlobContents[0].Name -split "/" # Only return the top item $PSObject = [PSCustomObject]@{ "Version" = $fileInfo[0] "URI" = $fileInfo[0] } return $PSObject } catch { Write-PSFMessage -Message "[<c='green'>$($application.Information.DisplayName)</c>] Error Occured: $($_)" -Level "Error" -Tag "Application", "$($application.Information.DisplayName)" -Target "Application Factory Service" throw $_ } } #EndRegion '.\Private\Get-AppFactoryAzureStorageAppItem.ps1' 33 #Region '.\Private\Get-AppFactoryAzureStorageFile.ps1' 0 function Get-AppFactoryAzureStorageFile{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][PSCustomObject]$application, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$destination, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) try{ $path = "$($application.SourceFiles.PackageSource)" $StorageBlobContents = Get-AzStorageBlob -Container $application.SourceFiles.StorageAccountContainerName -Context $script:appStorageContext -ErrorAction Stop | Where-Object {$_.Name -like "$($path)*"} foreach($blob in $StorageBlobContents){ $file = $blob.Name -split "/" if($file.length -gt 2){ $directoryPath = Join-path -Path $destination -ChildPath (($file[1..($file.length -2)]) -join "/") New-Item -Path $directoryPath -ItemType Directory -Force | Out-Null } else{ $directoryPath = $destination } $params = @{ Context = $script:appStorageContext Container = $application.SourceFiles.StorageAccountContainerName Blob = $blob.Name Destination = (Join-Path -Path $directoryPath -ChildPath $file[-1]) Force = $true } Get-AzStorageBlobContent @params | Out-Null } } catch { Write-PSFMessage -Message "[<c='green'>$($application.Information.DisplayName)</c>] Error Occured: $($_)" -Level "Error" -Tag "Application", "$($application.Information.DisplayName)" -Target "Application Factory Service" throw $_ } } #EndRegion '.\Private\Get-AppFactoryAzureStorageFile.ps1' 35 #Region '.\Private\Get-AppFactoryECNOAppItem.ps1' 0 function Get-AppFactoryECNOAppItem{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][PSCustomObject]$application, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) if($script:AppFactoryLogging){ Write-PSFMessage -Message "[<c='green'>$($application.Information.DisplayName)</c>] Looking for Sharepoint application." -Level $LogLevel -Tag "Application","$($application.Information.DisplayName)","PSADT" -Target "Application Factory Service" } # The PFX used to connect to the Sharepoint Configured $pfxPath = Join-Path -Path $script:AppFactoryLocalSupportFiles -ChildPath $script:AppFactorySharepointCertificate # Configuration for the PnP PowerShell Module $sharepointConfig = @{ "url" = "$($script:AppFactorysharepointurl)/sites/$($script:AppFactorysharepointsite)" "CertificatePath" = $pfxPath "CertificatePassword" = $script:AppFactorySharepointCertificateSecret.Password "ClientId" = $script:AppFactorySharepointClientID "Tenant" = $script:AppFactorySharepointTenant } try { Connect-PnPOnline @sharepointConfig } catch { if($script:AppFactoryLogging){ Write-PSFMessage -Message "Failed to connect to Sharepoint. Error: $($_)" -Level "Error" -Tag "Process","Sharepoint" -Target "Application Factory Service" } throw $_ } $listItems = Get-PnPListItem -List $script:AppFactorySharepointDocumentLibrary -PageSize 1000 | Where-Object {$_["FileDirRef"] -like "*$($application.SourceFiles.StorageAccountContainerName)"} $listItems = $listItems | Select-Object -Property @(@{name="FileLeafRef"; expr={$_["FileLeafRef"]}},@{name="FileRef"; expr={$_["FileRef"]}},@{name="FileDirRef"; expr={$_["FileDirRef"]}},@{name="Modified"; expr={$_["Modified"]}}) | Sort-Object -Property Modified -Descending $PSObject = [PSCustomObject]@{ "Version" = ($listItems[0].FileLeafRef -replace ".7z","").Trim() "URI" = $listItems[0].FileRef } return $PSObject } #EndRegion '.\Private\Get-AppFactoryECNOAppItem.ps1' 35 #Region '.\Private\Get-AppFactoryECNOFile.ps1' 0 function Get-AppFactoryECNOFile{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][PSCustomObject]$application, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$destination, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) # The PFX used to connect to the Sharepoint Configured $pfxPath = Join-Path -Path $script:AppFactoryLocalSupportFiles -ChildPath $script:AppFactorySharepointCertificate # Configuration for the PnP PowerShell Module $sharepointConfig = @{ "url" = "$($script:AppFactorysharepointurl)/sites/$($script:AppFactorysharepointsite)" "CertificatePath" = $pfxPath "CertificatePassword" = $script:AppFactorySharepointCertificateSecret.Password "ClientId" = $script:AppFactorySharepointClientID "Tenant" = $script:AppFactorySharepointTenant } try { Connect-PnPOnline @sharepointConfig } catch { if($script:AppFactoryLogging){ Write-PSFMessage -Message "Failed to connect to Sharepoint. Error: $($_)" -Level "Error" -Tag "Process","Sharepoint" -Target "Application Factory Service" } throw $_ } $fullpath = "$($script:AppFactorysharepointurl)$($application.SourceFiles.PackageSource)" $filename = "$($application.SourceFiles.PackageVersion).7z" Get-PnPFile -Url $fullpath -AsFile -Path $destination -Filename $filename -Force $7ZipPath = Join-Path -Path $script:AppFactorySupportFiles -ChildPath "7zr.exe" $7ZipFile = Join-Path -Path $destination -ChildPath $filename $vars = @{ "FilePath" = $7zipPath "ArgumentList" = "x `"$($7ZipFile)`" -aoa -o`"$($destination)`"" "Wait" = $true } Start-Process @vars Remove-Item -Path $7ZipFile -Force } #EndRegion '.\Private\Get-AppFactoryECNOFile.ps1' 38 #Region '.\Private\Get-AppFactoryEvergreenAppItem.ps1' 0 <# .DESCRIPTION This cmdlet is designed to interact with the evergreen powershell module to find the installers for evergreen based installers .PARAMETER application The application object that we are working for so that we can ensure that get the correct and current data .PARAMETER LogLevel If logging is enabled, what level of logging do we want, default is verbose. #> function Get-AppFactoryEvergreenAppItem{ [CmdletBinding()] [OutputType([PSCustomObject])] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][PSCustomObject]$application, [Parameter()][ValidateSet("Output","Verbose")][string]$LogLevel = "Verbose" ) if($script:AppFactoryLogging){ Write-PSFMessage -Message "[<c='green'>$($application.Information.DisplayName)</c>] Looking for Evergreen Application with AppID: <c='green'>$($application.SourceFiles.AppID)</c>" -Level $LogLevel -Tag "Application","$($application.Information.DisplayName)","Evergreen" -Target "Application Factory Service" } # Construct array list to build the dynamic filter list $FilterList = [System.Collections.Generic.List[PSCustomObject]]@() # Process known filter properties and add them to array list if present on current object if ($Application.SourceFiles.FilterOptions.Architecture) { if($script:AppFactoryLogging){ Write-PSFMessage -Message "[<c='green'>$($application.Information.DisplayName)</c>] Architecture Filter: <c='green'>$($Application.SourceFiles.FilterOptions.Architecture)</c>" -Level $LogLevel -Tag "Application","$($application.Information.DisplayName)","Evergreen" -Target "Application Factory Service" } $FilterList.Add("`$PSItem.Architecture -eq ""$($Application.SourceFiles.FilterOptions.Architecture)""") | Out-Null } if ($Application.SourceFiles.FilterOptions.Platform) { if($script:AppFactoryLogging){ Write-PSFMessage -Message "[<c='green'>$($application.Information.DisplayName)</c>] Platform Filter: <c='green'>$($Application.SourceFiles.FilterOptions.Platform)</c>" -Level $LogLevel -Tag "Application","$($application.Information.DisplayName)","Evergreen" -Target "Application Factory Service" } $FilterList.Add("`$PSItem.Platform -eq ""$($Application.SourceFiles.FilterOptions.Platform)""") | Out-Null } if ($Application.SourceFiles.FilterOptions.Channel) { if($script:AppFactoryLogging){ Write-PSFMessage -Message "[<c='green'>$($application.Information.DisplayName)</c>] Channel Filter: <c='green'>$($Application.SourceFiles.FilterOptions.Channel)</c>" -Level $LogLevel -Tag "Application","$($application.Information.DisplayName)","Evergreen" -Target "Application Factory Service" } $FilterList.Add("`$PSItem.Channel -eq ""$($Application.SourceFiles.FilterOptions.Channel)""") | Out-Null } if ($Application.SourceFiles.FilterOptions.Type) { if($script:AppFactoryLogging){ Write-PSFMessage -Message "[<c='green'>$($application.Information.DisplayName)</c>] Type Filter: <c='green'>$($Application.SourceFiles.FilterOptions.Type)</c>" -Level $LogLevel -Tag "Application","$($application.Information.DisplayName)","Evergreen" -Target "Application Factory Service" } $FilterList.Add("`$PSItem.Type -eq ""$($Application.SourceFiles.FilterOptions.Type)""") | Out-Null } if ($Application.SourceFiles.FilterOptions.InstallerType) { if($script:AppFactoryLogging){ Write-PSFMessage -Message "[<c='green'>$($application.Information.DisplayName)</c>] InstallerType Filter: <c='green'>$($Application.SourceFiles.FilterOptions.InstallerType)</c>" -Level $LogLevel -Tag "Application","$($application.Information.DisplayName)","Evergreen" -Target "Application Factory Service" } $FilterList.Add("`$PSItem.InstallerType -eq ""$($Application.SourceFiles.FilterOptions.InstallerType)""") | Out-Null } if ($Application.SourceFiles.FilterOptions.Release) { if($script:AppFactoryLogging){ Write-PSFMessage -Message "[<c='green'>$($application.Information.DisplayName)</c>] Release Filter: <c='green'>$($Application.SourceFiles.FilterOptions.Release)</c>" -Level $LogLevel -Tag "Application","$($application.Information.DisplayName)","Evergreen" -Target "Application Factory Service" } $FilterList.Add("`$PSItem.Release -eq ""$($Application.SourceFiles.FilterOptions.Release)""") | Out-Null } if ($Application.SourceFiles.FilterOptions.Language) { if($script:AppFactoryLogging){ Write-PSFMessage -Message "[<c='green'>$($application.Information.DisplayName)</c>] Language Filter: <c='green'>$($Application.SourceFiles.FilterOptions.Language)</c>" -Level $LogLevel -Tag "Application","$($application.Information.DisplayName)","Evergreen" -Target "Application Factory Service" } $FilterList.Add("`$PSItem.Language -eq ""$($Application.SourceFiles.FilterOptions.Language)""") | Out-Null } if ($Application.SourceFiles.FilterOptions.ImageType) { if($script:AppFactoryLogging){ Write-PSFMessage -Message "[<c='green'>$($application.Information.DisplayName)</c>] ImageType Filter: <c='green'>$($Application.SourceFiles.FilterOptions.ImageType)</c>" -Level $LogLevel -Tag "Application","$($application.Information.DisplayName)","Evergreen" -Target "Application Factory Service" } $FilterList.Add("`$PSItem.ImageType -eq ""$($Application.SourceFiles.FilterOptions.ImageType)""") | Out-Null } # Construct script block from filter list array $FilterExpression = [scriptblock]::Create(($FilterList -join " -and ")) # Get the evergreen app based on dynamic filter list if($FilterList.Count -gt 0){ $EvergreenApp = Get-EvergreenApp -Name $application.SourceFiles.AppID | Where-Object -FilterScript $FilterExpression | Sort-Object Version -Descending | Select-Object -first 1 } else{ $EvergreenApp = Get-EvergreenApp -Name $application.SourceFiles.AppID | Sort-Object Version -Descending | Select-Object -first 1 } # Only return the top item $PSObject = [PSCustomObject]@{ "Version" = $EvergreenApp.version "URI" = $EvergreenApp.URI } return $PSObject } #EndRegion '.\Private\Get-AppFactoryEvergreenAppItem.ps1' 87 #Region '.\Private\Get-AppFactoryExtraFiles.ps1' 0 function Get-AppFactoryExtraFiles{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][PSCustomObject]$application, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$destination, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) try{ foreach($container in $Application.SourceFiles.ExtraFiles){ #$path = "$($application.SourceFiles.PackageSource)" $StorageBlobContents = Get-AzStorageBlob -Container $container -Context $script:appStorageContext -ErrorAction Stop foreach($blob in $StorageBlobContents){ $file = $blob.Name -split "/" if($file.length -gt 2){ $directoryPath = Join-path -Path $destination -ChildPath (($file[1..($file.length -2)]) -join "/") New-Item -Path $directoryPath -ItemType Directory -Force | Out-Null } else{ $directoryPath = $destination } $params = @{ Context = $script:appStorageContext Container = $container Blob = $blob.Name Destination = (Join-Path -Path $directoryPath -ChildPath $file[-1]) Force = $true } Get-AzStorageBlobContent @params | Out-Null } } } catch { Write-PSFMessage -Message "[<c='green'>$($application.Information.DisplayName)</c>] Error Occured: $($_)" -Level "Error" -Tag "Application", "$($application.Information.DisplayName)" -Target "Application Factory Service" throw $_ } } #EndRegion '.\Private\Get-AppFactoryExtraFiles.ps1' 37 #Region '.\Private\Get-AppFactoryLocalStorageAppItem.ps1' 0 <# .DESCRIPTION This cmdlet is designed to download contacts from Azure Storage Account .PARAMETER application The application object that we are working for so that we can ensure that get the correct and current data .PARAMETER LogLevel If logging is enabled, what level of logging do we want, default is verbose. #> function Get-AppFactoryLocalStorageAppItem { [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][PSCustomObject]$application, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) try { if ($script:AppFactoryLogging) { Write-PSFMessage -Message "[<c='green'>$($application.Information.DisplayName)</c>] Getting Local Storage based application" -Level $LogLevel -Tag "Application", "$($application.Information.DisplayName)", "AzureStorage" -Target "Application Factory Service" } $localAppPath = Join-Path -Path $script:AppFactorySourceDir -ChildPath "LocalInstallers" -AdditionalChildPath $application.SourceFiles.StorageAccountContainerName $localAppList = Get-ChildItem -Path $localAppPath | Sort-Object LastWriteTime -Descending # Only return the top item $PSObject = [PSCustomObject]@{ "Version" = $localAppList[0].Name "URI" = $localAppList[0].FullName } return $PSObject } catch { Write-PSFMessage -Message "[<c='green'>$($application.Information.DisplayName)</c>] Error Occured: $($_)" -Level "Error" -Tag "Application", "$($application.Information.DisplayName)" -Target "Application Factory Service" throw $_ } } #EndRegion '.\Private\Get-AppFactoryLocalStorageAppItem.ps1' 33 #Region '.\Private\Get-AppFactoryPSADTAppItem.ps1' 0 <# .DESCRIPTION This cmdlet is designed to download contacts from Azure Storage Account .PARAMETER application The application object that we are working for so that we can ensure that get the correct and current data .PARAMETER storageContext The azure storage context that has permissions to upload to the Azure Storage Account .PARAMETER workingFolder Path to the working folder for the process .PARAMETER LogLevel If logging is enabled, what level of logging do we want, default is verbose. #> function Get-AppFactoryPSADTAppItem { [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][PSCustomObject]$application, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) if($script:AppFactoryLogging){ Write-PSFMessage -Message "[<c='green'>$($application.Information.DisplayName)</c>] Looking for PSADT application." -Level $LogLevel -Tag "Application","$($application.Information.DisplayName)","PSADT" -Target "Application Factory Service" } if($null -eq $application.Information.AppVersion -or $application.Information.AppVersion -eq "<replaced_by_build>"){ $version = "1.0" } else{ $version = $application.Information.AppVersion } $AppItem = [PSCustomObject]@{ "Version" = $version "URI" = $null } return $AppItem } #EndRegion '.\Private\Get-AppFactoryPSADTAppItem.ps1' 34 #Region '.\Private\Get-AppFactorySharepointAppItem.ps1' 0 function Get-AppFactorySharepointAppItem{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][PSCustomObject]$application, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) if($script:AppFactoryLogging){ Write-PSFMessage -Message "[<c='green'>$($application.Information.DisplayName)</c>] Looking for Sharepoint application." -Level $LogLevel -Tag "Application","$($application.Information.DisplayName)","PSADT" -Target "Application Factory Service" } # The PFX used to connect to the Sharepoint Configured $pfxPath = Join-Path -Path $script:AppFactoryLocalSupportFiles -ChildPath $script:AppFactorySharepointCertificate # Configuration for the PnP PowerShell Module $sharepointConfig = @{ "url" = "$($script:AppFactorysharepointurl)/sites/$($script:AppFactorysharepointsite)" "CertificatePath" = $pfxPath "CertificatePassword" = $script:AppFactorySharepointCertificateSecret.Password "ClientId" = $script:AppFactorySharepointClientID "Tenant" = $script:AppFactorySharepointTenant } try { Connect-PnPOnline @sharepointConfig } catch { if($script:AppFactoryLogging){ Write-PSFMessage -Message "Failed to connect to Sharepoint. Error: $($_)" -Level "Error" -Tag "Process","Sharepoint" -Target "Application Factory Service" } throw $_ } $listItems = Get-PnPListItem -List $script:AppFactorySharepointDocumentLibrary -PageSize 1000 | Where-Object {$_["FileDirRef"] -like "*$($application.SourceFiles.StorageAccountContainerName)"} $listItems = $listItems | Select-Object -Property @(@{name="FileLeafRef"; expr={$_["FileLeafRef"]}},@{name="FileRef"; expr={$_["FileRef"]}},@{name="FileDirRef"; expr={$_["FileDirRef"]}},@{name="Modified"; expr={$_["Modified"]}}) | Sort-Object -Property Modified -Descending $PSObject = [PSCustomObject]@{ "Version" = $listItems[0].FileLeafRef "URI" = $listItems[0].FileRef } return $PSObject } #EndRegion '.\Private\Get-AppFactorySharepointAppItem.ps1' 35 #Region '.\Private\Get-AppFactorySharepointFile.ps1' 0 function Get-AppFactorySharepointFile{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][PSCustomObject]$application, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$destination, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) # The PFX used to connect to the Sharepoint Configured $pfxPath = Join-Path -Path $script:AppFactoryLocalSupportFiles -ChildPath $script:AppFactorySharepointCertificate # Configuration for the PnP PowerShell Module $sharepointConfig = @{ "url" = "$($script:AppFactorysharepointurl)/sites/$($script:AppFactorysharepointsite)" "CertificatePath" = $pfxPath "CertificatePassword" = $script:AppFactorySharepointCertificateSecret.Password "ClientId" = $script:AppFactorySharepointClientID "Tenant" = $script:AppFactorySharepointTenant } try { Connect-PnPOnline @sharepointConfig } catch { if($script:AppFactoryLogging){ Write-PSFMessage -Message "Failed to connect to Sharepoint. Error: $($_)" -Level "Error" -Tag "Process","Sharepoint" -Target "Application Factory Service" } throw $_ } $listItems = Get-PnPListItem -List $script:AppFactorySharepointDocumentLibrary -PageSize 1000 | Where-Object {$_["FileDirRef"] -eq "$($application.SourceFiles.PackageSource)"} $listItems = $listItems | Select-Object -Property @(@{name="FileLeafRef"; expr={$_["FileLeafRef"]}},@{name="FileRef"; expr={$_["FileRef"]}}) foreach($item in $listItems){ $fullpath = "$($script:AppFactorysharepointurl)$($application.SourceFiles.PackageSource)/$($item.FileLeafRef)" Get-PnPFile -Url $fullpath -AsFile -Path $destination -Filename $item.FileLeafRef -Force } } #EndRegion '.\Private\Get-AppFactorySharepointFile.ps1' 32 #Region '.\Private\Get-AppFactoryWinGetAppItem.ps1' 0 function Get-AppFactoryWinGetAppItem{ [CmdletBinding()] [OutputType([PSCustomObject])] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][PSCustomObject]$application, [Parameter()][ValidateSet("Output","Verbose")][string]$LogLevel = "Verbose" ) # Create the argument and then run the winget $arguments = @("search", "$($application.SourceFiles.AppID)") $winget = & "winget" $arguments | Out-String -Stream # Confirm that a package was found foreach ($RowItem in $winget) { if ($RowItem -eq "No package found matching input criteria.") { if($script:AppFactoryLogging){ Write-PSFMessage -Message "[$($application.Information.DisplayName)] No package found matching specified id: <c='green'>$($application.SourceFiles.AppId)</c>" -Level "Error" -Tag "Process","Winget" -Target "Application Factory Service" } return $null } } # Now look for the specific item and get the details and parse them out $arguments = @("show", "$($application.SourceFiles.AppID)") $winget = & "winget" $arguments | Out-String -Stream $PSObject = [PSCustomObject]@{ "Version" = ($winget | Where-Object { $PSItem -match "^Version\:.*(?<AppVersion>(\d+(\.\d+){0,3}))$" }).Replace("Version:", "").Trim() "URI" = (($winget | Where-Object { $PSItem -match "^.*(Download|Installer) Url\:.*$" }) -replace "(Download|Installer) Url:", "").Trim() } return $PSObject } #EndRegion '.\Private\Get-AppFactoryWinGetAppItem.ps1' 29 #Region '.\Private\Get-ClientAppConfig.ps1' 0 function Get-ClientAppConfig{ [CmdletBinding()] [OutputType([System.Collections.Generic.List[PSCustomObject]])] param( [Parameter(Mandatory = $true)][PSCustomObject]$application, [Parameter()][PSCustomObject]$customConfig, [Parameter()][string]$audience = "Public", [Parameter()][ValidateSet("Output","Verbose")][string]$LogLevel = "Verbose" ) if($audience -eq "Public"){ $AppAudience = "Public" } else{ $AppAudience = "Private" } # Defaults for each application $defaultConfig = [PSCustomObject]@{ "AddToIntune" = $false "AvailableAssignments" = @() "AvailableExceptions" = @() "RequiredAssignments" = @() "RequiredExceptions" = @() "UninstallAssignments" = @() "UninstallExceptions" = @() "UnassignPrevious" = $false "CopyPrevious" = $false "KeepPrevious" = 0 "foreground" = $false "filters" = @{} "espprofiles" = @() "container" = $AppAudience "GUID" = $application.GUID "IntuneAppName" = $application.Information.DisplayName "AppVersion" = $null "InteractiveInstall" = $false "InteractiveUninstall" = $false } if($null -ne $customConfig){ $customConfig.PSObject.Properties | Where-Object {$_.Name -ne "Value"} | ForEach-Object { $defaultConfig.$($_.Name) = $_.Value } } if($null -eq $defaultConfig.AppVersion){ $temp = ($script:PublishedAppList.$audience | Where-Object {$_.Name -like "$($application.GUID)/*/App.json"}).Name $AppVersions = ([regex]::Matches($temp,"/(.*?)/App.json")).Groups.Value | Where-Object {$_ -notlike "*App.json"} $defaultConfig.AppVersion = $AppVersions | Sort-Object -Descending | Select-Object -First 1 } return $defaultConfig } #EndRegion '.\Private\Get-ClientAppConfig.ps1' 50 #Region '.\Private\Get-MSIMetaData.ps1' 0 function Get-MSIMetaData { <# .SYNOPSIS Retrieve a specific MSI property value from MSI based installation file. .DESCRIPTION Retrieve a specific MSI property value from MSI based installation file. .PARAMETER Path Specify the full path to a MSI based installation file. .PARAMETER Property Specify the MSI database property to retrieve it's value. .NOTES Author: Nickolaj Andersen Contact: @NickolajA Created: 2020-01-04 Updated: 2020-01-04 Version history: 1.0.0 - (2020-01-27) Function created #> [CmdletBinding(SupportsShouldProcess = $true)] param( [parameter(Mandatory = $true, HelpMessage = "Specify the full path to a MSI based installation file.")] [ValidateNotNullOrEmpty()] [System.IO.FileInfo]$Path, [parameter(Mandatory = $true, HelpMessage = "Specify the MSI database property to retrieve it's value.")] [ValidateNotNullOrEmpty()] [ValidateSet("ProductCode", "ProductVersion", "ProductName", "Manufacturer", "ProductLanguage", "FullVersion")] [string]$Property ) Process { try { # Read property from MSI database $WindowsInstaller = New-Object -ComObject WindowsInstaller.Installer $MSIDatabase = $WindowsInstaller.GetType().InvokeMember("OpenDatabase", "InvokeMethod", $null, $WindowsInstaller, @($Path.FullName, 0)) $Query = "SELECT Value FROM Property WHERE Property = '$($Property)'" $View = $MSIDatabase.GetType().InvokeMember("OpenView", "InvokeMethod", $null, $MSIDatabase, ($Query)) $View.GetType().InvokeMember("Execute", "InvokeMethod", $null, $View, $null) $Record = $View.GetType().InvokeMember("Fetch", "InvokeMethod", $null, $View, $null) $Value = $Record.GetType().InvokeMember("StringData", "GetProperty", $null, $Record, 1) # Commit database and close view $MSIDatabase.GetType().InvokeMember("Commit", "InvokeMethod", $null, $MSIDatabase, $null) $View.GetType().InvokeMember("Close", "InvokeMethod", $null, $View, $null) $MSIDatabase = $null $View = $null # Return the value return $Value } catch { Write-Warning -Message $_.Exception.Message; break } } End { # Run garbage collection and release ComObject [System.Runtime.Interopservices.Marshal]::ReleaseComObject($WindowsInstaller) | Out-Null [System.GC]::Collect() } } #EndRegion '.\Private\Get-MSIMetaData.ps1' 65 #Region '.\Private\Invoke-Process.ps1' 0 function Invoke-Process{ [CmdletBinding()] [OutputType([System.Collections.Generic.List[PSCustomObject]])] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][String]$FileName, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][String]$Arguments, [Parameter()][ValidateNotNullOrEmpty()][bool]$CreateNoWindow = $false, [Parameter()][ValidateNotNullOrEmpty()][bool]$UseShellExecute = $true, [Parameter()][ValidateNotNullOrEmpty()][bool]$RedirectStandardOutput = $false, [Parameter()][ValidateNotNullOrEmpty()][bool]$RedirectStandardError = $false ) try{ $ProcessInfo = New-object -TypeName "System.Diagnostics.ProcessStartInfo" $ProcessInfo.FileName = $FileName $ProcessInfo.CreateNoWindow = $CreateNoWindow $ProcessInfo.UseShellExecute = $UseShellExecute $ProcessInfo.RedirectStandardOutput = $RedirectStandardOutput $ProcessInfo.RedirectStandardError = $RedirectStandardError $ProcessInfo.Arguments = $Arguments $Process = New-Object -TypeName "System.Diagnostics.Process" $Process.StartInfo = $ProcessInfo [void]$Process.Start() $Process.WaitForExit() return [PSCustomObject]@{ ExitCode = $Process.ExitCode } } catch{ throw $_ } } #EndRegion '.\Private\Invoke-Process.ps1' 32 #Region '.\Private\New-AppFactoryAppFolder.ps1' 0 <# .DESCRIPTION This cmdlet is designed to create a new application to be handled by the automated process .PARAMETER DisplayName The DisplayName of the application that we are creating .PARAMETER force Continue even if the folder already exists, overwriting the current details .PARAMETER LogLevel If logging is enabled, what level of logging do we want, default is verbose. .EXAMPLE Create a new application folder New-AppFactoryAppFolder -DisplayName "### DisplayName ###" -LogLevel "Output" #> function New-AppFactoryAppFolder { [CmdletBinding()] [OutputType([string])] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][String]$DisplayName, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][String]$folderName, [Parameter()][bool]$force, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) # Path to the new app folder $appFolderPath = Join-Path -Path $script:AppFactorySourceDir -ChildPath "Apps" -AdditionalChildPath $folderName if ($script:AppFactoryLogging) { Write-PSFMessage -Message "[$($DisplayName)] Template folder used <c='green'>$($script:AppFactorySupportTemplateFolder)</c>" -Level $LogLevel -Tag "Application", "$($DisplayName)" -Target "Application Factory Service" } # Create New Application Folder try { if ((Test-Path $appFolderPath) -and -not $force) { throw "Folder Already Exists $($script:AppFactorySupportTemplateFolder) and force was not set" } New-Item -Path $appFolderPath -ItemType Directory -Force | Out-Null Write-PSFMessage -Message "[$($DisplayName)] Created application folder <c='green'>$($appFolderPath)</c>" -Level $LogLevel -Tag "Application", "$($DisplayName)" -Target "Application Factory Service" } catch { Write-PSFMessage -Message "Error Encountered: $($_)" -Level "Error" -Tag "Application", "$($DisplayName)" -Target "Application Factory Service" throw $_ } try { # Placeholder Icon File $iconFile = Join-Path -Path $script:AppFactorySupportTemplateFolder -ChildPath "PSADT" -AdditionalChildPath "Assets", "AppIcon.png" Copy-Item -Path $iconFile -Destination "$($appFolderPath)\Icon.png" -ErrorAction Stop -Force Write-PSFMessage -Message "[$($DisplayName)] Copying Placeholder Icon file to <c='green'>$($appFolderPath)</c>" -Level $LogLevel -Tag "Application", "$($DisplayName)" -Target "Application Factory Service" } catch { Remove-Item -Path $appFolderPath -Force Write-PSFMessage -Message "Error Encountered: $($_)" -Level "Error" -Tag "Application", "$($DisplayName)" -Target "Application Factory Service" throw $_ } return $appFolderPath } #EndRegion '.\Private\New-AppFactoryAppFolder.ps1' 55 #Region '.\Private\New-AppFactoryClientDetectionRule.ps1' 0 function New-AppFactoryClientDetectionRule { [CmdletBinding()] [OutputType([System.Collections.Generic.List[PSCustomObject]])] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][PSCustomObject]$application, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$ApplicationFolder, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) $rules = [System.Collections.Generic.List[PSCustomObject]]@() $DetectionRules = $application.DetectionRule foreach ($DetectionRuleItem in $DetectionRules) { switch ($DetectionRuleItem.Type) { "MSI" { if ($script:AppFactoryClientLogging) { Write-PSFMessage -Message "[<c='green'>$($application.Information.DisplayName)</c>] Adding MSI Detection Rule" -Level $LogLevel -Tag "Applications", "Intune", "$($application.Information.DisplayName)" -Target "Application Factory Client" } $DetectionRule = [ordered]@{ "@odata.type" = "#microsoft.graph.win32LobAppProductCodeDetection" "productCode" = $DetectionRuleItem.ProductCode "productVersionOperator" = $DetectionRuleItem.ProductVersionOperator "productVersion" = $DetectionRuleItem.ProductVersion } } "Script" { if ($script:AppFactoryClientLogging) { Write-PSFMessage -Message "[<c='green'>$($application.Information.DisplayName)</c>] Adding Script Detection Rule" -Level $LogLevel -Tag "Applications", "Intune", "$($application.Information.DisplayName)" -Target "Application Factory Client" } # Create a PowerShell script based detection rule $ScriptContent = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes((Get-Content -Path (Join-Path -Path $ApplicationFolder -ChildPath $DetectionRuleItem.ScriptFile) -Raw -Encoding UTF8))) $DetectionRule = [ordered]@{ "@odata.type" = "#microsoft.graph.win32LobAppPowerShellScriptDetection" "enforceSignatureCheck" = [System.Convert]::ToBoolean($DetectionRuleItem.EnforceSignatureCheck) "runAs32Bit" = [System.Convert]::ToBoolean($DetectionRuleItem.RunAs32Bit) "scriptContent" = $ScriptContent } } "Registry" { if ($script:AppFactoryClientLogging) { Write-PSFMessage -Message "[<c='green'>$($application.Information.DisplayName)</c>] Adding Registry Detection Rule" -Level $LogLevel -Tag "Applications", "Intune", "$($application.Information.DisplayName)" -Target "Application Factory Client" } switch ($DetectionRuleItem.DetectionMethod) { "Existence" { $DetectionRule = [ordered]@{ "@odata.type" = "#microsoft.graph.win32LobAppRegistryDetection" "operator" = "notConfigured" "detectionValue" = $null "check32BitOn64System" = [System.Convert]::ToBoolean($DetectionRuleItem.Check32BitOn64System) "keyPath" = $DetectionRuleItem.KeyPath "valueName" = $DetectionRuleItem.ValueName "detectionType" = $DetectionRuleItem.DetectionType } } "VersionComparison" { $DetectionRule = [ordered]@{ "@odata.type" = "#microsoft.graph.win32LobAppRegistryDetection" "operator" = $DetectionRuleItem.Operator "detectionValue" = $DetectionRuleItem.Value "check32BitOn64System" = [System.Convert]::ToBoolean($DetectionRuleItem.Check32BitOn64System) "keyPath" = $DetectionRuleItem.KeyPath "valueName" = $DetectionRuleItem.ValueName "detectionType" = "version" } } "StringComparison" { $DetectionRule = [ordered]@{ "@odata.type" = "#microsoft.graph.win32LobAppRegistryDetection" "operator" = $DetectionRuleItem.Operator "detectionValue" = $DetectionRuleItem.Value "check32BitOn64System" = [System.Convert]::ToBoolean($DetectionRuleItem.Check32BitOn64System) "keyPath" = $DetectionRuleItem.KeyPath "valueName" = $DetectionRuleItem.ValueName "detectionType" = "string" } } "IntegerComparison" { $DetectionRule = [ordered]@{ "@odata.type" = "#microsoft.graph.win32LobAppRegistryDetection" "operator" = $DetectionRuleItem.Operator "detectionValue" = $DetectionRuleItem.Value "check32BitOn64System" = [System.Convert]::ToBoolean($DetectionRuleItem.Check32BitOn64System) "keyPath" = $DetectionRuleItem.KeyPath "valueName" = $DetectionRuleItem.ValueName "detectionType" = "integer" } } } } "File" { if ($script:AppFactoryClientLogging) { Write-PSFMessage -Message "[<c='green'>$($application.Information.DisplayName)</c>] Adding File Detection Rule" -Level $LogLevel -Tag "Applications", "Intune", "$($application.Information.DisplayName)" -Target "Application Factory Client" } switch ($DetectionRuleItem.DetectionMethod) { "Existence" { $DetectionRule = [ordered]@{ "@odata.type" = "#microsoft.graph.win32LobAppFileSystemDetection" "operator" = "notConfigured" "detectionValue" = $null "path" = $DetectionRuleItem.Path "fileOrFolderName" = $DetectionRuleItem.FileOrFolder "check32BitOn64System" = [System.Convert]::ToBoolean($DetectionRuleItem.Check32BitOn64System) "detectionType" = $DetectionRuleItem.DetectionType } } "DateModified" { [datatime]$InputObject = [datatime]$DetectionRuleItem.DateTimeValue $DateValueString = Get-Date -Year $InputObject.Year -Month $InputObject.Month -Day $InputObject.Day -Hour $InputObject.Hour -Minute $InputObject.Minute -Second $InputObject.Second -UFormat '+%Y-%m-%dT%H:%M:%S.000Z' $DetectionRule = [ordered]@{ "@odata.type" = "#microsoft.graph.win32LobAppFileSystemDetection" "operator" = $DetectionRuleItem.Operator "detectionValue" = $DateValueString "path" = $DetectionRuleItem.Path "fileOrFolderName" = $DetectionRuleItem.FileOrFolder "check32BitOn64System" = [System.Convert]::ToBoolean($DetectionRuleItem.Check32BitOn64System) "detectionType" = "modifiedDate" } } "DateCreated" { [datatime]$InputObject = [datatime]$DetectionRuleItem.DateTimeValue $DateValueString = Get-Date -Year $InputObject.Year -Month $InputObject.Month -Day $InputObject.Day -Hour $InputObject.Hour -Minute $InputObject.Minute -Second $InputObject.Second -UFormat '+%Y-%m-%dT%H:%M:%S.000Z' $DetectionRule = [ordered]@{ "@odata.type" = "#microsoft.graph.win32LobAppFileSystemDetection" "operator" = $DetectionRuleItem.Operator "detectionValue" = $DateValueString "path" = $DetectionRuleItem.Path "fileOrFolderName" = $DetectionRuleItem.FileOrFolder "check32BitOn64System" = [System.Convert]::ToBoolean($DetectionRuleItem.Check32BitOn64System) "detectionType" = "createdDate" } } "Version" { $DetectionRule = [ordered]@{ "@odata.type" = "#microsoft.graph.win32LobAppFileSystemDetection" "operator" = $DetectionRuleItem.Operator "detectionValue" = $DetectionRuleItem.VersionValue "path" = $DetectionRuleItem.Path "fileOrFolderName" = $DetectionRuleItem.FileOrFolder "check32BitOn64System" = [System.Convert]::ToBoolean($DetectionRuleItem.Check32BitOn64System) "detectionType" = "version" } } "Size" { $DetectionRule = [ordered]@{ "@odata.type" = "#microsoft.graph.win32LobAppFileSystemDetection" "operator" = $DetectionRuleItem.Operator "detectionValue" = $DetectionRuleItem.SizeInMBValue "path" = $DetectionRuleItem.Path "fileOrFolderName" = $DetectionRuleItem.FileOrFolder "check32BitOn64System" = [System.Convert]::ToBoolean($DetectionRuleItem.Check32BitOn64System) "detectionType" = "sizeInMB" } } } } } # Add detection rule to list $rules.Add($DetectionRule) | Out-Null } return $rules } #EndRegion '.\Private\New-AppFactoryClientDetectionRule.ps1' 161 #Region '.\Private\New-AppFactoryClientRequirementRule.ps1' 0 function New-AppFactoryClientRequirementRule { [CmdletBinding()] [OutputType([ordered])] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][PSCustomObject]$application, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) # Construct table for supported architectures $ArchitectureTable = @{ "x64" = "x64" "x86" = "x86" "All" = "x64,x86" } # Construct table for supported operating systems $OperatingSystemTable = @{ "W10_1607" = "1607" "W10_1703" = "1703" "W10_1709" = "1709" "W10_1803" = "1803" "W10_1809" = "1809" "W10_1903" = "1903" "W10_1909" = "1909" "W10_2004" = "2004" "W10_20H2" = "2H20" "W10_21H1" = "21H1" "W10_21H2" = "Windows10_21H2" "W10_22H2" = "Windows10_22H2" "W11_21H2" = "Windows11_21H2" "W11_22H2" = "Windows11_22H2" "W11_23H2" = "Windows11_23H2" } $RequirementRule = [ordered]@{ "applicableArchitectures" = $ArchitectureTable[$application.RequirementRule.Architecture] "minimumSupportedWindowsRelease" = $OperatingSystemTable[$application.RequirementRule.MinimumSupportedWindowsRelease] } return $RequirementRule } #EndRegion '.\Private\New-AppFactoryClientRequirementRule.ps1' 38 #Region '.\Private\New-PSUGUIInputCode.ps1' 0 function New-PSUGUIInputCode{ [cmdletbinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$id, [Parameter()][Object[]]$Code, [Parameter()][int]$item_height = 400, [Parameter()][int]$item_colspan = 1, [Parameter()][string]$language = "powershell" ) New-UDElement -Tag "td" -Attributes @{ Style = @{ "vertical-align" = "bottom"; } Colspan = $item_colspan } -Content { New-UDCodeEditor -Height $item_height -Language $language -id $id -Code ($Code -Join "`n") } } #EndRegion '.\Private\New-PSUGUIInputCode.ps1' 19 #Region '.\Private\New-PSUGUIInputSelectGroup.ps1' 0 function New-PSUGUIInputSelectGroup { [cmdletbinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$Label, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$id, [Parameter()][string[]]$options, [Parameter()][string[]]$defaultValue = @(), [Parameter()][string]$placeholder = "", [Parameter()][string]$onchangeAction = "", [Parameter()][int]$label_width = 20, [Parameter()][int]$item_width = 30, [Parameter()][int]$label_colspan = 1, [Parameter()][int]$item_colspan = 1, [Parameter()][switch]$multiselect ) New-UDElement -Tag "td" -Content { New-UDElement -Tag "span" -ClassName "appfactory-label" -Content { New-UDTypography -Text $Label } } -Attributes @{"style" = @{"width" = "$($label_width)%"; "vertical-align" = "bottom"; }; Colspan = $label_colspan } New-UDElement -Tag "td" -Content { New-UDSelect -Multiple:$($multiselect.isPresent) -ClassName "appfactory-select" -DefaultValue $defaultValue -id $id -FullWidth -Option { foreach ($option in $options) { New-UDSelectOption -Name $option -Value $option } } -OnChange { switch ($onchangeAction) { "SourceSelection" { Set-UDElement -Id "SourceSelectionFields" -Content {} Set-UDElement -Id "SourceSelectionFields" -Content { switch ((Get-UDElement $id).value) { "StorageAccount" { New-PSUGUISourceStorageAccount } "Sharepoint" { New-PSUGUISourceSharepoint } "Winget" { New-PSUGUISourceWinget } "Evergreen" { New-PSUGUISourceEvergreen } "ECNO" { New-PSUGUISourceECNO } "LocalStorage" { New-PSUGUISourceStorageAccount } "PSADT" { New-PSUGUISourcePSADT } } } } "InstallSelection" { Set-UDElement -Id "InstallSelectionFields" -Content {} Set-UDElement -Id "InstallSelectionFields" -Content { switch ((Get-UDElement $id).value) { "Script" { New-PSUGUIInstallScript } "EXE" { New-PSUGUIInstallEXE } "MSI" { New-PSUGUIInstallMSI } } } } "UninstallSelection" { Set-UDElement -Id "UninstallSelectionFields" -Content {} Set-UDElement -Id "UninstallSelectionFields" -Content { switch ((Get-UDElement $id).value) { "Script" { New-PSUGUIUnInstallScript } "EXE" { New-PSUGUIUnInstallEXE } "MSI" { New-PSUGUIUnInstallMSI } "Name" { New-PSUGUIUninstallName } "GUID" { New-PSUGUIUninstallGUID } } } } "DetectionSelection" { Set-UDElement -Id "DetectionSelectionFields" -Content {} Set-UDElement -Id "DetectionSelectionFields" -Content { switch ((Get-UDElement $id).value) { "MSI" { New-PSUGUIDetectionMSI } "Registry Version" { New-PSUGUIDetectionRegistryVersion } "Registry Existance" { New-PSUGUIDetectionRegistryExistance } "Script" { New-PSUGUIDetectionScript } } } } "AvailableVersionsSelection" { Set-UDElement -id "DeleteVersion" -Properties @{ Disabled = $false } } default {} } } } -Attributes @{"style" = @{"width" = "$($item_width)%"; "vertical-align" = "bottom" }; Colspan = $item_colspan } } #EndRegion '.\Private\New-PSUGUIInputSelectGroup.ps1' 121 #Region '.\Private\New-PSUGUIInputTextboxGroup.ps1' 0 function New-PSUGUIInputTextboxGroup { [cmdletbinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$Label, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$id, [Parameter()][switch]$disabled, [Parameter()][string]$placeholder = "", [Parameter()][int]$label_width = 20, [Parameter()][int]$item_width = 30, [Parameter()][int]$label_colspan = 1, [Parameter()][int]$item_colspan = 1, [Parameter()][int]$rows = 5 ) New-UDElement -Tag "td" -Attributes @{ Style = @{ width = $label_width "vertical-align" = "top"; } Colspan = $label_colspan } -Content { New-UDElement -Tag "span" -ClassName "appfactory-label" -Content { New-UDTypography -Text $Label } } New-UDElement -Tag "td" -Attributes @{ Style = @{ width = $item_width "vertical-align" = "bottom"; } Colspan = $item_colspan } -Content { New-UDTextbox -Multiline -Rows $rows -FullWidth -id $id -ClassName "appfactory-textbox" -Disabled:$disabled.IsPresent } } #EndRegion '.\Private\New-PSUGUIInputTextboxGroup.ps1' 33 #Region '.\Private\New-PSUGUIInputTextGroup.ps1' 0 function New-PSUGUIInputTextGroup { [cmdletbinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$Label, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$id, [Parameter()][switch]$disabled, [Parameter()][string]$value = "", [Parameter()][string]$placeholder = "", [Parameter()][int]$label_width = 20, [Parameter()][int]$item_width = 30, [Parameter()][int]$label_colspan = 1, [Parameter()][int]$item_colspan = 1 ) New-UDElement -Tag "td" -Attributes @{ Style = @{ width = $label_width "vertical-align" = "bottom"; } Colspan = $label_colspan } -Content { New-UDElement -Tag "span" -ClassName "appfactory-label" -Content { New-UDTypography -Text $Label } } New-UDElement -Tag "td" -Attributes @{ Style = @{ width = $item_width "vertical-align" = "bottom"; } Colspan = $item_colspan } -Content { #New-UDElement -Tag "input" -ClassName "appfactory-input" -id $id -Attributes @{ # value = $value # placeholder = $placeholder # "aria-label" = $placeholder # type = "input" #} New-UDTextBox -FullWidth -Placeholder $placeholder -id $id -Value $value -ClassName "appfactory-input" -Disabled:$disabled.IsPresent } } #EndRegion '.\Private\New-PSUGUIInputTextGroup.ps1' 39 #Region '.\Private\New-PSUGUISwitch.ps1' 0 function New-PSUGUISwitch{ [cmdletbinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$Label, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$id, [Parameter()][switch]$checked, [Parameter()][int]$label_width = 20, [Parameter()][int]$label_colspan = 1, [Parameter()][int]$item_colspan = 1 ) New-UDElement -Tag "td" -Attributes @{ Style = @{ width = $label_width "vertical-align" = "bottom"; } Colspan = $label_colspan } -Content { New-UDElement -Tag "span" -ClassName "appfactory-label" -Content { New-UDTypography -Text $Label } } New-UDElement -Tag "td" -Attributes @{ Style = @{ width = $item_width "vertical-align" = "bottom"; } Colspan = $item_colspan } -Content { New-UDSwitch -id $id -Checked $checked.IsPresent } } #EndRegion '.\Private\New-PSUGUISwitch.ps1' 30 #Region '.\Private\New-PSUGUUploadIcon.ps1' 0 function New-PSUGUUploadIcon { [cmdletbinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$Label, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$id, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$output, [Parameter()][string]$default_icon, [Parameter()][string]$placeholder = "", [Parameter()][int]$label_width = 20, [Parameter()][int]$item_width = 30, [Parameter()][int]$label_colspan = 1, [Parameter()][int]$item_colspan = 1 ) New-UDElement -Tag "td" -Attributes @{ Style = @{ width = $label_width "vertical-align" = "top"; } Colspan = $label_colspan } -Content { New-UDElement -Tag "span" -ClassName "appfactory-label" -Content { New-UDTypography -Text $Label } } New-UDElement -Tag "td" -Attributes @{ Style = @{ width = $item_width "vertical-align" = "bottom"; } Colspan = $item_colspan } -Content { if([String]::IsNullOrWhiteSpace($default_icon)){ $default_icon = Join-Path -Path $script:AppFactorySupportTemplateFolder -ChildPath "PSADT" -AdditionalChildPath "Assets","AppIcon.png" } New-UDElement -Tag "table" -Content { New-UDElement -Tag "tr" -Content { New-UDElement -Tag "td" -Content { New-UDUpload -Id $id -Text $placeholder -OnUpload { $Data = $Body | ConvertFrom-Json $bytes = [System.Convert]::FromBase64String($Data.Data) [System.IO.File]::WriteAllBytes("$($env:TEMP)\PSUApp_Icon.png", $bytes) Set-UDElement -Id "imgdiv" -Content {} Set-UDElement -Id "imgdiv" -Content { New-UDImage -Id "appimage" -Path "$($env:TEMP)\PSUApp_Icon.png" -Width 50 -Height 50 } } } New-UDElement -Tag "td" -Content { New-UDElement -Tag "div" -Id "imgdiv" -Content { New-UDImage -Id "appimage" -Path $default_icon -Width 50 -Height 50 } } } } #New-UDTextbox -Multiline -Rows 6 -FullWidth -id $id -ClassName "appfactory-textbox" } } #EndRegion '.\Private\New-PSUGUUploadIcon.ps1' 56 #Region '.\Private\Write-AppConfiguration.ps1' 0 function Write-AppConfiguration{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][PSCustomObject]$configfile, [Parameter()][ValidateSet("Output","Verbose")][string]$LogLevel = "Verbose" ) try{ $outputPath = Join-Path -Path $script:AppFactorySourceDir -ChildPath "Apps" -AdditionalChildPath $configfile.Information.AppFolderName, "ApplicationConfig.json" $configfile | ConvertTo-Json -Depth 10 | Out-File -FilePath $outputPath if($script:AppFactoryLogging){ Write-PSFMessage -Message "[$($configfile.Information.DisplayName)] Wrote default app configuration" -Level $LogLevel -Tag "Application", "$($configfile.Information.DisplayName)", "$($configFIle.GUID)" -Target "AppFactory" } } catch{ throw $_ } } #EndRegion '.\Private\Write-AppConfiguration.ps1' 18 #Region '.\Public\Add-AppFactoryClientAppAssignments.ps1' 0 function Add-AppFactoryClientAppAssignments { [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][PSCustomObject]$application, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$intuneid, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) if ($script:AppFactoryClientLogging) { Write-PSFMessage -Message "[<c='green'>$($application.IntuneAppName)</c>] Adding Application Assignments" -Level $LogLevel -Tag "Applications", "Intune", "$($application.IntuneAppName)" -Target "Application Factory Client" } $commonVariables = @{ "applicationid" = $intuneid "filters" = $application.filters } try { if ($application.AvailableAssignments -ne "") { Add-GraphIntuneAppAssignment @commonVariables -intent available -groups $application.AvailableAssignments -foreground $application.foreground } if ($application.AvailableExceptions -ne "") { Add-GraphIntuneAppAssignment @commonVariables -intent available -groups $application.AvailableExceptions -exclude } if ($application.RequiredAssignments -ne "") { Add-GraphIntuneAppAssignment @commonVariables -intent required -groups $application.RequiredAssignments -foreground $application.foreground } if ($application.RequiredExceptions -ne "") { Add-GraphIntuneAppAssignment @commonVariables -intent required -groups $application.RequiredExceptions -exclude } if ($application.UninstallAssignments -ne "") { Add-GraphIntuneAppAssignment @commonVariables -intent uninstall -groups $application.UninstallAssignments -foreground $application.foreground } if ($application.UninstallExceptions -ne "") { Add-GraphIntuneAppAssignment @commonVariables -intent uninstall -groups $application.UninstallExceptions -exclude } } catch { $_ } } #EndRegion '.\Public\Add-AppFactoryClientAppAssignments.ps1' 27 #Region '.\Public\Add-AppFactoryClientESPAssignment.ps1' 0 function Add-AppFactoryClientESPAssignment { [CmdletBinding()] [OutputType([System.Collections.Generic.List[PSCustomObject]])] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][PSCustomObject]$application, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$intuneid, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) # Loop through applications if ($application.espprofiles) { foreach ($esp in $application.espprofiles) { if ($script:AppFactoryClientLogging) { Write-PSFMessage -Message "[<c='green'>$($application.IntuneAppName)</c>] Assigning application to ESP Porfile $($esp)" -Level $LogLevel -Tag "Applications", "Intune", "$($application.IntuneAppName)" -Target "Application Factory Client" } Add-GraphIntuneAppAddToESP -displayName $esp -applicationid $intuneid } } } #EndRegion '.\Public\Add-AppFactoryClientESPAssignment.ps1' 19 #Region '.\Public\Compare-AppFactoryClientAppVersions.ps1' 0 function Compare-AppFactoryClientAppVersions { [CmdletBinding()] [OutputType([System.Collections.Generic.List[PSCustomObject]])] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][System.Collections.Generic.List[PSCustomObject]]$applicationList, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][System.Collections.Generic.List[PSCustomObject]]$intuneApplications, [Parameter()][ValidateNotNullOrEmpty()][switch]$force, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) # Create blank list to store the applications that we will be moving forward with. $applications = [System.Collections.Generic.List[PSCustomObject]]@() # Loop through the applications foreach ($application in $applicationList) { if ($script:AppFactoryClientLogging) { Write-PSFMessage -Message "[<c='green'>$($application.IntuneAppName)</c>] Comparing Version (<c='green'>$($application.AppVersion)</c>) between expected and published" -Level $LogLevel -Tag "Applications", "$($application.IntuneAppName)" -Target "Application Factory Client" } $intuneApplication = $intuneApplications | Where-Object { $_.Notes -match "STSID:$($application.GUID)" } if($null -eq $intuneApplication.displayVersion -or $application.AppVersion -notin $intuneApplication.displayVersion){ if ($script:AppFactoryClientLogging) { Write-PSFMessage -Message "[<c='green'>$($application.IntuneAppName)</c>] Current Published Versions: <c='green'>$($intuneApplication.displayVersion -join ",")</c>" -Level $LogLevel -Tag "Applications", "$($application.IntuneAppName)" -Target "Application Factory Client" Write-PSFMessage -Message "[<c='green'>$($application.IntuneAppName)</c>] Current Expected Version: <c='green'>$($application.AppVersion)</c>" -Level $LogLevel -Tag "Applications", "$($application.IntuneAppName)" -Target "Application Factory Client" } $applications.Add($application) | Out-Null } else{ Write-PSFMessage -Message "[<c='green'>$($application.IntuneAppName)</c>] Application version <c='green'>$($intuneApplication.displayVersion -join ",")</c> already published" -Level $LogLevel -Tag "Applications", "$($application.IntuneAppName)" -Target "Application Factory Client" } } return $applications } #EndRegion '.\Public\Compare-AppFactoryClientAppVersions.ps1' 31 #Region '.\Public\Copy-AppFactoryClientAppAssignments.ps1' 0 function Copy-AppFactoryClientAppAssignments { [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][PSCustomObject]$application, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$intuneid, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][System.Collections.Generic.List[PSCustomObject]]$intuneApplications, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) if ($application.CopyPrevious) { if ($script:AppFactoryClientLogging) { Write-PSFMessage -Message "[<c='green'>$($application.IntuneAppName)</c>] Copying Application Assignments" -Level $LogLevel -Tag "Applications", "Intune", "$($application.IntuneAppName)" -Target "Application Factory Client" } $applications = $intuneApplications | Where-Object { $_.Notes -match "STSID:$($application.GUID)" } | Select-Object id, displayname, @{Label = "Version"; expression = { [version]$_.displayversion } } | Sort-Object -Property "Version" -Descending if ($applications.count -gt 0) { Copy-GraphIntuneAppAssignments -applicationid $intuneid -copyapplicationid $applications[0].id } } } #EndRegion '.\Public\Copy-AppFactoryClientAppAssignments.ps1' 19 #Region '.\Public\Get-AppFactoryApp.ps1' 0 <# .DESCRIPTION This cmdlet returns a list of applications that are part of the packaging process .PARAMETER appSource This is a filtering parameter for specific appsources .PARAMETER GUID The unique identifier for the application that we want to work with .PARAMETER displayName The unique name of the application that we want to work with .PARAMETER AppID This is a filtering parameter for specific AppID .PARAMETER AppPublisher This is a filtering parameter for specific application publisher .PARAMETER StorageAccountContainerName This is a filtering parameter for specific application azure storage container .PARAMETER publishTo This is a filtering parameter for specific organization .PARAMETER public This is a filtering parameter for all public applications .PARAMETER LogLevel If logging is enabled, what level of logging do we want, default is verbose. .EXAMPLE Get a list of all applications Get-AppFactoryApp Get a list of specific application sources Get-AppFactoryApp -appSource "### Application Source ###" Get a list of applications based on GUID Get-AppFactoryApp -GUID "### GUID ###" Get a list of applications based on AppID Get-AppFactoryApp -AppID "### AppID ###" Get a list of applications based on Application Publisher Get-AppFactoryApp -AppPublisher "### Publisher ###" Get a list of applications based on Publish To a client Get-AppFactoryApp -publishTo "### Client ###" Get a list of all public applications Get-AppFactoryApp -public Get a list of all application with logging enabled Get-AppFactoryApp -LogLevel "Output" #> function Get-AppFactoryApp{ [CmdletBinding()] [OutputType([System.Collections.Generic.List[PSCustomObject]])] param( [Parameter()][ValidateSet("StorageAccount", "Sharepoint", "Winget", "Evergreen", "PSADT", "ECNO", "LocalStorage")][string]$appSource, [Parameter()][ValidateNotNullOrEmpty()][string]$appGUID, [Parameter()][ValidateNotNullOrEmpty()][string]$displayName, [Parameter()][ValidateNotNullOrEmpty()][string]$AppID, [Parameter()][ValidateNotNullOrEmpty()][string]$Publisher, [Parameter()][ValidateNotNullOrEmpty()][string]$StorageAccountContainerName, [Parameter()][ValidateNotNullOrEmpty()][string]$publishTo, [Parameter()][ValidateNotNullOrEmpty()][string]$dependsOn, [Parameter()][switch]$public, [Parameter()][switch]$active, [Parameter()][ValidateSet("Output","Verbose")][string]$LogLevel = "Verbose" ) # Get the path to where the application configs are stored $applicationFolders = Join-Path -Path $script:AppFactorySourceDir -ChildPath "Apps" # Get a list of all the configuration files for the applications $ApplicationConfigFiles = Get-Childitem -Path $applicationFolders -Recurse -Filter "ApplicationConfig.json" if($script:AppFactoryLogging){ Write-PSFMessage -Message "Retrieved Application Configurations at path <c='green'>$($applicationFolders)</c>" -Level $LogLevel -Tag "Application" -Target "Application Factory Service" } # Create an empty array to store the application objects $applicaitonList = [System.Collections.Generic.List[PSCustomObject]]@() # Perform any needed filtering based on passed variables foreach($file in $ApplicationConfigFiles){ $json = Get-Content $file.FullName | ConvertFrom-Json # If specific parameters are passed, filter the list of applications based on those parameters if($PSBoundParameters.ContainsKey("appGUID") -and $json.GUID -ne $appGUID){continue} if($PSBoundParameters.ContainsKey("appSource") -and $json.SourceFiles.appSource -ne $appSource){continue} if($PSBoundParameters.ContainsKey("displayName") -and $json.Information.displayName -notlike "$($displayName)"){continue} if($PSBoundParameters.ContainsKey("AppID") -and $json.SourceFiles.AppID -ne $AppID){continue} if($PSBoundParameters.ContainsKey("Publisher") -and $json.Information.Publisher -ne $AppPublisher){continue} if($PSBoundParameters.ContainsKey("StorageAccountContainerName") -and $json.SourceFiles.StorageAccountContainerName -ne $StorageAccountContainerName){continue} if($PSBoundParameters.ContainsKey("publishTo") -and $publishTo -notin $json.SourceFiles.publishTo){continue} if($PSBoundParameters.ContainsKey("dependsOn") -and $dependsOn -notin $json.SourceFiles.dependsOn){continue} if($PSBoundParameters.ContainsKey("dependsOn") -and $dependsOn -notin $json.SourceFiles.dependsOn){continue} if($active.IsPresent -and (-not $json.SourceFiles.Active)){continue} if($public.IsPresent -and $json.SourceFiles.publishTo.count -ne 0){continue} if($script:AppFactoryLogging){ Write-PSFMessage -Message "Reading Application: <c='green'>$($json.Information.displayName) ($($json.GUID))</c>"-Level $LogLevel -Tag "Application","$($json.displayName)","$($json.GUID)" -Target "Application Factory Service" } $applicaitonList.Add($json) | Out-Null } # Return the application list return $applicaitonList } #EndRegion '.\Public\Get-AppFactoryApp.ps1' 97 #Region '.\Public\Get-AppFactoryAppInstall.ps1' 0 function Get-AppFactoryAppInstall{ [CmdletBinding()] [OutputType([Hashtable])] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$appGUID, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) # Get the application Config $configfile = Get-AppFactoryApp -appGUID $appGUID -LogLevel $LogLevel if (-not ($configfile)) { throw "Application with GUID $($GUID) does not exist." } return $configfile.install } #EndRegion '.\Public\Get-AppFactoryAppInstall.ps1' 15 #Region '.\Public\Get-AppFactoryAppUninstall.ps1' 0 function Get-AppFactoryAppUninstall{ [CmdletBinding()] [OutputType([Hashtable])] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$appGUID, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) # Get the application Config $configfile = Get-AppFactoryApp -appGUID $appGUID -LogLevel $LogLevel if (-not ($configfile)) { throw "Application with GUID $($GUID) does not exist." } return $configfile.uninstall } #EndRegion '.\Public\Get-AppFactoryAppUninstall.ps1' 15 #Region '.\Public\Get-AppFactoryClientApp.ps1' 0 function Get-AppFactoryClientApp{ [CmdletBinding()] [OutputType([System.Collections.Generic.List[PSCustomObject]])] param( [Parameter()][string]$appGUID, [Parameter()][string]$AppName, [Parameter()][bool]$AddToIntune, [Parameter()][string]$AvailableAssignments, [Parameter()][string]$AvailableExceptions, [Parameter()][string]$RequiredAssignments, [Parameter()][string]$RequiredExceptions, [Parameter()][string]$UninstallAssignments, [Parameter()][string]$UninstallExceptions, [Parameter()][ValidateSet("Output","Verbose")][string]$LogLevel = "Verbose" ) # App Folders $applicationFolderPath = Join-Path -Path $script:AppFactoryClientSourceDir -ChildPath "Apps" # Get All Applications $applicationConfigFiles = Get-Childitem -Path $applicationFolderPath # Blank List for the Apps $applicationList = [System.Collections.Generic.List[PSCustomObject]]@() # Loop through the configuration and add to the list. foreach($file in $applicationConfigFiles){ $json = Get-Content $file.FullName | ConvertFrom-Json $skip = $false foreach($param in ($PSBoundParameters.GetEnumerator() | Where-Object {$_.Key -ne "LogLevel"})){ if($json.$($param.Key).getType().BaseType.Name -eq "Array"){ if($param.Value -notin $json.$($param.Key) ){$skip = $true; break} } else{ if($param.Value -ne $json.$($param.Key)){$skip = $true; break} } } if(-not $skip){ $applicationList.Add($json) | Out-Null } } return $applicationList } #EndRegion '.\Public\Get-AppFactoryClientApp.ps1' 40 #Region '.\Public\Get-AppFactoryClientAppFiles.ps1' 0 function Get-AppFactoryClientAppFiles { [CmdletBinding()] [OutputType([System.Collections.Generic.List[PSCustomObject]])] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][PSCustomObject]$applications, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) $downloadFolder = Join-Path -Path $script:AppFactoryClientWorkspace -ChildPath "Downloads" -AdditionalChildPath $application.IntuneAppName if(Test-Path $downloadFolder){ Remove-Item -Path $downloadFolder -Force -Recurse -ErrorAction SilentlyContinue } New-Item -Path $downloadFolder -ItemType Directory | Out-Null $container = $script:AppFactoryClientSASPublicContainerName $sas = $script:AppFactoryClientSASpublic if($application.container -ne $script:AppFactoryClientSASPublicContainerName){ $container = $script:AppFactoryClientSASOrganizationContainerName $sas = $script:AppFactoryClientSASorganization } $endpoint = "$($script:AppFactoryClientSASStoragePath)/$($container)/$($application.GUID)/$($application.AppVersion)" if($script:AppFactoryClientLogging){ Write-PSFMessage -Message "[<c='green'>$($application.IntuneAppName)</c>] Downloading files from $($endpoint)" -Level $LogLevel -Tag "Applications","$($application.IntuneAppName)" -Target "Application Factory Client" } $filelist = @("$($application.IntuneAppName).intunewin","App.json") foreach($file in $filelist){ try{ Invoke-WebRequest -Uri "$($endpoint)/$($file)?$($sas)" -OutFile "$($downloadFolder)\$($file)" | Out-Null } catch{ throw "[<c='green'>$($application.IntuneAppName)</c>] Failed to download $($file) from $($baseURI). $($_.Exception.Message)" } } $AppData = Get-Content "$($downloadFolder)\App.json" | ConvertFrom-JSON $downloadFiles = [System.Collections.Generic.List[String]]@() $downloadFiles.Add($AppData.PackageInformation.IconFile) | Out-Null if($AppData.DetectionRule.Type -eq "Script"){ $downloadFiles.Add($AppData.DetectionRule.ScriptFile) | Out-Null } foreach($file in $downloadFiles){ try{ Invoke-WebRequest -Uri "$($endpoint)/$($file)?$($sas)" -OutFile "$($downloadFolder)\$($file)" | Out-Null } catch{ throw "[<c='green'>$($application.IntuneAppName)</c>] Failed to download $($file) from $($baseURI). $($_.Exception.Message)" } } } #EndRegion '.\Public\Get-AppFactoryClientAppFiles.ps1' 47 #Region '.\Public\Get-AppFactoryClientAppList.ps1' 0 function Get-AppFactoryClientAppList { [CmdletBinding()] param( [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) # Where to save file $ApplicationFolder = Join-Path -Path $script:AppFactoryClientSourceDir -ChildPath "Apps" # Create the folder if it doesn't exist Remove-Item -Path $ApplicationFolder -Force -Recurse if (-not (Test-Path -Path $ApplicationFolder)) { New-Item -Path $ApplicationFolder -ItemType Directory | Out-Null } # What is the PSU Endpoint we should be using $PSUEndpoint = "$($script:AppFactoryClientApiEndpoint)/AppList" # Retrieve Data $headers = @{ "content-type" = "application/json" "authorization" = "bearer $(ConvertFrom-SecureString $script:AppFactoryClientAPISecret -AsPlainText)" } $applicationList = Invoke-RestMethod -Method "GET" -Uri $PSUEndpoint -Headers $headers -StatusCodeVariable "statusCode" foreach($application in $applicationList){ $applicationPath = Join-Path -Path $ApplicationFolder -ChildPath "$($application.IntuneAppName).json" $application | ConvertTo-Json -Depth 10 | Out-File -FilePath $applicationPath -Force } } #EndRegion '.\Public\Get-AppFactoryClientAppList.ps1' 27 #Region '.\Public\Get-AppFactoryClientGraphApp.ps1' 0 function Get-AppFactoryClientGraphApp{ [CmdletBinding()] [OutputType([System.Collections.Generic.List[PSCustomObject]])] param( [Parameter()][ValidateSet("Output","Verbose")][string]$LogLevel = "Verbose" ) Get-GraphAccessToken -clientID $script:AppFactoryClientClientID -tenantID $script:AppFactoryClientTenantID -clientSecret $script:AppFactoryClientAppRegSecret | Out-Null $intuneApplications = Get-GraphIntuneApp -type "microsoft.graph.win32LobApp" return $intuneApplications } #EndRegion '.\Public\Get-AppFactoryClientGraphApp.ps1' 11 #Region '.\Public\Get-AppFactoryClientSAS.ps1' 0 function Get-AppFactoryClientSAS{ [CmdletBinding()] param( [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) # What is the PSU Endpoint we should be using $PSUEndpoint = "$($script:AppFactoryClientApiEndpoint)/SAS" # Retrieve Data $headers = @{ "content-type" = "application/json" "authorization" = "bearer $(ConvertFrom-SecureString $script:AppFactoryClientAPISecret -AsPlainText)" } $sas = Invoke-RestMethod -Method "GET" -Uri $PSUEndpoint -Headers $headers -StatusCodeVariable "statusCode" $script:AppFactoryClientSASorganization = $sas.organization $script:AppFactoryClientSASPublicContainerName = $sas.PublicContainerName $script:AppFactoryClientSASStoragePath = $sas.StoragePath $script:AppFactoryClientSASOrganizationContainerName = $sas.OrganizationContainerName $script:AppFactoryClientSASpublic = $sas.public } #EndRegion '.\Public\Get-AppFactoryClientSAS.ps1' 20 #Region '.\Public\Get-AppFactoryInstaller.ps1' 0 function Get-AppFactoryInstaller { [CmdletBinding()] [OutputType([System.Collections.Generic.List[PSCustomObject]])] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][System.Collections.Generic.List[PSCustomObject]]$applicationList, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) # Create list to store results of the process $applications = [System.Collections.Generic.List[PSCustomObject]]@() foreach ($application in $applicationList) { try { $AppSetupFolderPath = Join-Path -Path $script:AppFactoryWorkspace -ChildPath "Installers" -AdditionalChildPath $application.Information.AppFolderName # Create path if it doesn't exist if (-not(Test-Path -Path $AppSetupFolderPath -PathType "Container")) { try { New-Item -Path $AppSetupFolderPath -ItemType "Container" -ErrorAction "Stop" | Out-Null } catch [System.Exception] { throw "[$($application.Information.DisplayName)] Failed to create '$($Path)' with error message: $($_.Exception.Message)" } } # Download installer file try { $OutFilePath = Join-Path -Path $AppSetupFolderPath -ChildPath $application.SourceFiles.AppSetupFileName if ($script:AppFactoryLogging) { Write-PSFMessage -Message "[<c='green'>$($application.Information.DisplayName)</c>] Downloading setupfile <c='green'>$($application.SourceFiles.PackageSource)</c>" -Level $LogLevel -Tag "Application", "$($application.Information.DisplayName)", "Download" -Target "Application Factory Service" } switch ($Application.SourceFiles.AppSource) { "ECNO" { Get-AppFactoryECNOFile -application $application -Destination $AppSetupFolderPath -LogLevel $LogLevel } "Sharepoint" { Get-AppFactorySharepointFile -application $application -Destination $AppSetupFolderPath -LogLevel $LogLevel } "LocalStorage" { Get-ChildItem -Path $application.SourceFiles.PackageSource | foreach-object {Copy-Item $_.FullName -Destination $AppSetupFolderPath -Force -ErrorAction "Stop" -Recurse} | Out-Null } "StorageAccount" { Get-AppFactoryAzureStorageFile -application $application -Destination $AppSetupFolderPath -LogLevel $LogLevel } "PSADT" {} default { Invoke-WebRequest -Uri $application.SourceFiles.PackageSource -OutFile $OutFilePath -UseBasicParsing -ErrorAction "Stop" } } } catch [System.Exception] { throw "[$($application.Information.DisplayName)] Failed to download file from '$($application.SourceFiles.PackageSource)' with error message: $($_.Exception.Message)" } } catch { if ($script:AppFactoryLogging) { Write-PSFMessage -Message $_ -Level "Error" -Tag "Application", "$($application.Information.DisplayName)", "Error" -Target "Application Factory Service" } continue } # Download Extra Files try{ if($Application.SourceFiles.ExtraFiles){ $OutFilePath = Join-Path -Path $AppSetupFolderPath -ChildPath $application.SourceFiles.AppSetupFileName Get-AppFactoryExtraFiles -application $application -Destination $AppSetupFolderPath -LogLevel $LogLevel } } catch { if ($script:AppFactoryLogging) { Write-PSFMessage -Message $_ -Level "Error" -Tag "Application", "$($application.Information.DisplayName)", "Error" -Target "Application Factory Service" } continue } if ($script:AppFactoryLogging) { Write-PSFMessage -Message "[<c='green'>$($application.Information.DisplayName)</c>] Successfully downloaded files." -Level $LogLevel -Tag "Application", "$($application.Information.DisplayName)", "WinGet" -Target "AppFactory" } $applications.Add($application) } return $applications } #EndRegion '.\Public\Get-AppFactoryInstaller.ps1' 78 #Region '.\Public\Get-AppFactoryPSUApplications.ps1' 0 function Get-AppFactoryPSUApplications { [cmdletbinding()] param() New-UDElement -Tag "figure" -ClassName "text-center" -Content { New-UDElement -Tag "h4" -ClassName "display-4" -Content { "Application Factory Applications" } } New-UDElement -Tag "div" -ClassName "container-fluid" -Content { New-UDElement -Tag "div" -ClassName "row justify-content-start" -Content { New-UDElement -Tag "div" -ClassName "col-5" -Content { New-UDElement -Tag "div" -ClassName "card-body rounded" -Content { New-UDTypography -Text "Application List" -Variant "h5" -ClassName "card-title rounded x-card-title" New-UDElement -Tag "div" -id "ApplicationList" -Content { Initialize-AppFactoryProcess -ApplicationServicePath $AppFactory_ApplicationPath New-UDDataGrid -id "ApplicationListTableData" -LoadRows { Initialize-AppFactoryProcess -ApplicationServicePath $AppFactory_ApplicationPath $ClientList = Get-AppFactoryServiceClient $TableData = Get-AppFactoryApp | Select-Object -Property @{Label = "ID"; expression = { $_.GUID } }, @{Label = "Name"; expression = { $_.Information.DisplayName } }, @{Label = "Availability"; expression = { if ($_.SourceFiles.publishTo.count -eq 0) { "All" } else { $orgList = [System.Collections.Generic.List[String]]::new() foreach ($obj in $_.SourceFiles.publishTo) { $orgList.Add(($ClientList | Where-Object { $_.GUID -eq $obj }).Name) | Out-Null } $orgList -join ", " } } }, @{Label = "Active"; expression = { $_.SourceFiles.Active } }, @{Label = "Source"; expression = { $_.SourceFiles.AppSource } }, @{Label = "Updated"; expression = { (Get-Date -Date $_.SourceFiles.LastUpdate).ToString("yyyy/MM/dd HH:mm:ss") } }, Information, SourceFiles, Install, Uninstall, RequirementRule, Program, DetectionRule $TableData | Out-UDDataGridData -Context $EventData -TotalRows $Rows.Length } -Columns @( New-UDDataGridColumn -Field Name -Flex 1.5 -Render { $EventData.Name New-UDElement -tag "div" -content {} -Attributes @{style = @{width = "10px"}} if($null -ne $EventData.Information.InformationURL -and $EventData.Information.InformationURL -ne "") { New-UDLink -Url $EventData.Information.InformationURL -OpenInNewWindow -Content { New-UDImage -URL "/assets/images/information.png" -Attributes @{ alt = "$($EventData.Information.InformationURL)" style = @{ width = "20px" height = "20px" } } } } New-UDElement -tag "div" -content {} -Attributes @{style = @{width = "10px"}} if($null -ne $EventData.Information.PrivacyURL -and $EventData.Information.PrivacyURL -ne "") { New-UDLink -Url $EventData.Information.PrivacyURL -OpenInNewWindow -Content { New-UDImage -URL "/assets/images/privacy.png" -Attributes @{ alt = "$($EventData.Information.PrivacyURL)" style = @{ width = "20px" height = "20px" } } } } } New-UDDataGridColumn -Field Availability -Flex 2.0 New-UDDataGridColumn -Field Active -Flex 1.0 New-UDDataGridColumn -Field Updated -Flex 1.0 New-UDDataGridColumn -Field Source -Flex 0 -DisableColumnMenu -Render {} -DisableExport -DisableReorder -Hide New-UDDataGridColumn -Field Information -Flex 0 -DisableColumnMenu -Render {} -DisableExport -DisableReorder -Hide New-UDDataGridColumn -Field SourceFiles -Flex 0 -DisableColumnMenu -Render {} -DisableExport -DisableReorder -Hide New-UDDataGridColumn -Field Install -Flex 0 -DisableColumnMenu -Render {} -DisableExport -DisableReorder -Hide New-UDDataGridColumn -Field Uninstall -Flex 0 -DisableColumnMenu -Render {} -DisableExport -DisableReorder -Hide New-UDDataGridColumn -Field RequirementRule -Flex 0 -DisableColumnMenu -Render {} -DisableExport -DisableReorder -Hide New-UDDataGridColumn -Field DetectionRule -Flex 0 -DisableColumnMenu -Render {} -DisableExport -DisableReorder -Hide New-UDDataGridColumn -Field Program -Flex 0 -DisableColumnMenu -Render {} -DisableExport -DisableReorder -Hide ) -StripedRows -AutoHeight $true -PageSize 10 -RowsPerPageOptions @(10,25,50,100,1000) -ShowPagination -DefaultSortColumn Name -OnSelectionChange { Import-Module -Name $AppFactory_Module -Force $TableData = Get-UDElement -Id "ApplicationListTableData" $selectedRow = ((Get-UDElement -Id "ApplicationListTableData").selection)[0] $selectedRowData = $TableData.Data.Rows | Where-Object { $_.ID -eq $selectedRow } $AppVersions = Get-AppFactoryServiceAppVersions -appGUID $selectedRow -AllAppList $script:PublishedAppList # Standard Text Based Elements to Set $setTextElements = @( @{ id = "ApplicationGUID" value = $selectedRow type = "text" placeholder = "" }, @{ id = "ApplicationName" value = $selectedRowData.Information.DisplayName type = "text" placeholder = "Application Name" }, @{ id = "Publisher" value = $selectedRowData.Information.Publisher type = "text" placeholder = "Publisher Name" }, @{ id = "PrivacyURL" value = $selectedRowData.Information.PrivacyURL type = "text" placeholder = "Information URL" }, @{ id = "InformationURL" value = $selectedRowData.Information.InformationURL type = "text" placeholder = "Privacy URL" }, @{ id = "Owner" value = $selectedRowData.Information.Owner type = "text" placeholder = "Owner Name" } ) foreach ($item in $setTextElements) { Set-UDElement -id $item.id -Properties @{ value = $item.value } } if ($selectedRowData.Availability -ne "All") { $ClientListValue = $selectedRowData.Availability -split ", " } else { $ClientListValue = "" } # Standard Select Based Elements to Set $setSelectElements = @( @{ id = "Client" value = $ClientListValue }, @{ id = "Architecture" Value = $selectedRowData.RequirementRule.Architecture }, @{ id = "MinimumSupportedWindowsRelease" Value = $selectedRowData.RequirementRule.MinimumSupportedWindowsRelease }, @{ id = "Source" Value = $selectedRowData.SourceFiles.AppSource }, @{ id = "Install" Value = $selectedRowData.Install.type }, @{ id = "Uninstall" Value = $selectedRowData.Uninstall.type }, @{ id = "InstallExperience" Value = $selectedRowData.Program.InstallExperience.tolower() } ) foreach ($item in $setSelectElements) { Set-UDElement -id $item.id -Properties @{ Value = $item.Value } } # Start Text Box Based Elements to Set $setTextboxElements = @( @{ id = "Description" value = $selectedRowData.Information.Description }, @{ id = "Notes" value = $selectedRowData.Information.Notes } ) foreach ($item in $setTextboxElements) { Set-UDElement -id $item.id -Properties @{ Value = $item.Value } } # Start Switch Based Elements to Set $setSwitchElements = @( @{ id = "Active" Checked = $selectedRowData.SourceFiles.Active }, @{ id = "pauseUpdate" Checked = $selectedRowData.SourceFiles.pauseUpdate } ) foreach ($item in $setSwitchElements) { Set-UDElement -id $item.id -Properties @{ Checked = $item.Checked } } # Available versions based on application Set-UDElement -id "AvailableVersions" -Properties @{ Options = @( foreach ($version in ($AppVersions | Sort-Object -Descending)) { New-UDSelectOption -Name $version -Value $version } ) } # Detection drop down Set-UDElement -Id "DetectionSelectionFields" -Content {} Set-UDElement -Id "DetectionSelectionFields" -Content { switch ($selectedRowData.DetectionRule.Type) { "MSI" { Set-UDElement -id "Detection" -Properties @{ Value = "MSI" } New-PSUGUIDetectionMSI -SourceData $selectedRowData.DetectionRule } "Registry" { if ($selectedRowData.DetectionRule.DetectionMethod -eq "VersionComparison") { Set-UDElement -id "Detection" -Properties @{ Value = "Registry Version" } New-PSUGUIDetectionRegistryVersion -SourceData $selectedRowData.DetectionRule } else { Set-UDElement -id "Detection" -Properties @{ Value = "Registry Existance" } New-PSUGUIDetectionRegistryExistance -SourceData $selectedRowData.DetectionRule } } "Script" { Set-UDElement -id "Detection" -Properties @{ Value = "Script" } $scriptPath = Join-Path -Path $script:AppFactorySourceDir -ChildPath "Apps" -AdditionalChildPath $selectedRowData.information.appFolderName, "Detection.ps1" -ErrorAction SilentlyContinue New-PSUGUIDetectionScript -SourceData $selectedRowData.DetectionRule -scriptPath $scriptPath } } } # Set Icon FIle $ApplicationPath = Join-Path -Path $script:AppFactorySourceDir -ChildPath "Apps" -AdditionalChildPath $selectedRowData.Information.AppFolderName $AppIconFile = Join-Path -Path $ApplicationPath -ChildPath "Icon.png" Set-UDElement -Id "imgdiv" -Content {} Set-UDElement -Id "imgdiv" -Content { New-UDImage -Id "appimage" -Path "$($AppIconFile)" -Width 50 -Height 50 } # Set Source Files Set-UDElement -Id "SourceSelectionFields" -Content {} Set-UDElement -Id "SourceSelectionFields" -Content { switch ($selectedRowData.sourceFiles.appSource) { "StorageAccount" { New-PSUGUISourceStorageAccount -SourceData $selectedRowData.sourcefiles } "Sharepoint" { New-PSUGUISourceSharepoint -SourceData $selectedRowData.sourcefiles } "Winget" { New-PSUGUISourceWinget -SourceData $selectedRowData.sourcefiles } "LocalStorage" { New-PSUGUISourceStorageAccount -SourceData $selectedRowData.sourcefiles } "ECNO" { New-PSUGUISourceECNO -SourceData $selectedRowData.sourcefiles } "Evergreen" { New-PSUGUISourceEvergreen -SourceData $selectedRowData.sourcefiles } "PSADT" { New-PSUGUISourcePSADT -SourceData $selectedRowData.Information } "StorageAccount - PowerShell Script" { New-PSUGUISourceStorageAccountScript -SourceData $selectedRowData.Information } } } # Set Install Data Set-UDElement -Id "InstallSelectionFields" -Content {} Set-UDElement -Id "InstallSelectionFields" -Content { switch ($selectedRowData.Install.type) { "Script" { New-PSUGUIInstallScript -SourceData $selectedRowData.install } "EXE" { New-PSUGUIInstallEXE -SourceData $selectedRowData.install } "MSI" { New-PSUGUIInstallMSI -SourceData $selectedRowData.install } "Powershell" { New-PSUGUIInstallPowershell -SourceData $selectedRowData.install -versiondata $selectedRowData.Information } } } # Set Uninstall Data Set-UDElement -Id "UninstallSelectionFields" -Content {} Set-UDElement -Id "UninstallSelectionFields" -Content { switch ($selectedRowData.Uninstall.type) { "Script" { New-PSUGUIUnInstallScript -SourceData $selectedRowData.Uninstall } "EXE" { New-PSUGUIUnInstallEXE -SourceData $selectedRowData.Uninstall } "MSI" { New-PSUGUIUnInstallMSI -SourceData $selectedRowData.Uninstall } "Name" { New-PSUGUIUninstallName -SourceData $selectedRowData.Uninstall } "GUID" { New-PSUGUIUninstallGUID -SourceData $selectedRowData.Uninstall } "Powershell" { New-PSUGUIUninstallPowershell -SourceData $selectedRowData.uninstall } } } Set-UDElement -id "UpdateApplication" -Properties @{ Disabled = $false } Set-UDElement -id "DeleteApplication" -Properties @{ Disabled = $false } Set-UDElement -id "DeleteVersion" -Properties @{ Disabled = $true } Set-UDElement -id "AvailableVersions" -Properties @{ Value = "" } } } } } New-UDElement -Tag "div" -ClassName "col-1" -Content {} New-UDElement -Tag "div" -ClassName "col-6" -Content { New-UDElement -Tag "div" -ClassName "card-body rounded" -Content { New-UDTypography -Text "Application Details" -Variant "h5" -ClassName "card-title rounded x-card-title" New-UDButton -Id "NewApplication" -Text "New Application" -ClassName "btn btn-primary" -OnClick { $global:submitApp = $true $AppInformation = Get-PSUGUIAppInfo $AppInstall = Get-PSUGUIAppInstallInfo $AppUninstall = Get-PSUGUIAppUninstallInfo $AppDetection = Get-PSUGuiAppDetectionInfo if ($global:submitApp) { $AppInformation.Add("AppFolderName", $AppInformation.displayName) | Out-Null $AppFolder = Join-Path -Path $script:AppFactorySourceDir -ChildPath "Apps" -AdditionalChildPath $AppInformation.AppFolderName $IconFileData = Get-UDElement -Id "IconFile" $IconDesination = Join-Path -Path $AppFolder -ChildPath "Icon.png" if ([String]::IsNullOrWhiteSpace($IconFileData.value)) { $IconPath = Join-Path -Path $script:AppFactorySupportTemplateFolder -ChildPath "PSADT" -AdditionalChildPath "Assets", "AppIcon.png" } else { $IconPath = "$($env:TEMP)\PSUApp_Icon.png" } $application = New-AppFactoryApp @AppInformation Set-AppFactoryAppInstall -appGUID $application.GUID @AppInstall Set-AppFactoryAppUninstall -appGUID $application.GUID @AppUninstall Set-AppFactoryAppDetectionRule -appGUID $application.GUID @AppDetection if($AppDetection.Type -eq "Script"){ $ScriptData = (Get-UDElement -Id "Detection_Script").code $DetectionPS = Join-Path -Path $AppFolder -ChildPath "Detection.ps1" $ScriptData | Out-File -FilePath $DetectionPS -Force } Copy-Item -Path $IconPath -Destination $IconDesination -Force Set-UDElement -id "AppTabs" -Content {New-PSUGUIAppTabs} Sync-UDElement -Id 'ApplicationListTableData' } } New-UDButton -Id "UpdateApplication" -Text "Update Application" -Disabled -ClassName "btn btn-primary" -OnClick { Import-Module -Name $AppFactory_Module -Force Initialize-AppFactoryProcess -ApplicationServicePath $AppFactory_ApplicationPath $global:submitApp = $true $AppInformation = Get-PSUGUIAppInfo $AppInstall = Get-PSUGUIAppInstallInfo $AppUninstall = Get-PSUGUIAppUninstallInfo $AppDetection = Get-PSUGuiAppDetectionInfo if ($global:submitApp) { $selectedRow = ((Get-UDElement -Id "ApplicationListTableData").selection)[0] $application = Set-AppFactoryApp -appGUID $selectedRow @AppInformation $AppFolder = Join-Path -Path $script:AppFactorySourceDir -ChildPath "Apps" -AdditionalChildPath $application.Information.AppFolderName $IconFileData = Get-UDElement -Id "IconFile" $IconDesination = Join-Path -Path $AppFolder -ChildPath "Icon.png" if (-not [String]::IsNullOrWhiteSpace($IconFileData.value)) { $IconPath = "$($env:TEMP)\PSUApp_Icon.png" Copy-Item -Path $IconPath -Destination $IconDesination -Force } Set-AppFactoryAppInstall -appGUID $application.GUID @AppInstall Set-AppFactoryAppUninstall -appGUID $application.GUID @AppUninstall Set-AppFactoryAppDetectionRule -appGUID $application.GUID @AppDetection if($AppDetection.Type -eq "Script"){ $ScriptData = (Get-UDElement -Id "Detection_Script").code $DetectionPS = Join-Path -Path $AppFolder -ChildPath "Detection.ps1" $ScriptData | Out-File -FilePath $DetectionPS -Force } Sync-UDElement -Id 'ApplicationListTableData' } } New-UDButton -Id "DeleteApplication" -Text "Delete Application" -Disabled -ClassName "btn btn-primary" -OnClick { Show-UDModal -MaxWidth lg -Content { Import-Module -Name $AppFactory_Module -Force Initialize-AppFactoryProcess -ApplicationServicePath $AppFactory_ApplicationPath $TableData = Get-UDElement -Id "ApplicationListTableData" $selectedRow = ((Get-UDElement -Id "ApplicationListTableData").selection)[0] $selectedRowData = $TableData.Data.Rows | Where-Object { $_.ID -eq $selectedRow } $displayName = $selectedRowData.Information.DisplayName New-UDTypography -Text "Are you sure you want to delete this application? $($displayName)" -Variant "h5" New-UDButton -Text "Yes" -ClassName "btn btn-primary" -OnClick { Remove-AppFactoryApp -appGUID $selectedRow Sync-UDElement -Id 'ApplicationListTableData' Set-UDElement -id "AppTabs" -Content {New-PSUGUIAppTabs} Hide-UDModal } New-UDButton -Text "No" -ClassName "btn btn-primary" -OnClick { Hide-UDModal } } } New-UDButton -Id "DeleteVersion" -Text "Delete Version" -Disabled -ClassName "btn btn-primary" -OnClick { Show-UDModal -MaxWidth lg -Content { Import-Module -Name $AppFactory_Module -Force Initialize-AppFactoryProcess -ApplicationServicePath $AppFactory_ApplicationPath $TableData = Get-UDElement -Id "ApplicationListTableData" $selectedRow = ((Get-UDElement -Id "ApplicationListTableData").selection)[0] $selectedRowData = $TableData.Data.Rows | Where-Object { $_.ID -eq $selectedRow } $displayName = $selectedRowData.Information.DisplayName $versionToDelete = (Get-UDElement -id "AvailableVersions").Value New-UDTypography -Text "Are you sure you want to delete this version $($versionToDelete) from $($displayName)?" -Variant "h5" New-UDButton -Text "Yes" -ClassName "btn btn-primary" -OnClick { Remove-AppFactoryServiceAppVersions -appGUID $selectedRow -version $versionToDelete -AllAppList $script:PublishedAppList $AppVersions = Get-AppFactoryServiceAppVersions -appGUID $selectedRow -AllAppList $script:PublishedAppList Set-UDElement -id "AvailableVersions" -Properties @{ Options = @( foreach ($version in ($AppVersions | Sort-Object -Descending)) { New-UDSelectOption -Name $version -Value $version } ) } Hide-UDModal } New-UDButton -Text "No" -ClassName "btn btn-primary" -OnClick { Hide-UDModal } } } New-UDElement -id "AppTabs" -Content { New-PSUGUIAppTabs } } New-UDElement -Tag "pre" -id "datahelper" -Content {} } } } } #EndRegion '.\Public\Get-AppFactoryPSUApplications.ps1' 450 #Region '.\Public\Get-AppfactoryPSUClientApplications.ps1' 0 function Get-AppfactoryPSUClientApplications { [cmdletbinding()] param() Initialize-AppFactoryProcess -ApplicationServicePath $AppFactory_ApplicationPath $ids = ($Roles -match "(^([0-9A-Fa-f]{8}[-]?[0-9A-Fa-f]{4}[-]?[0-9A-Fa-f]{4}[-]?[0-9A-Fa-f]{4}[-]?[0-9A-Fa-f]{12})$)") $clients = Get-AppFactoryServiceClient if ($roles.Contains($PSU_GUI_AdminRole)) { $defaultValue = $clients[0].GUID } else { $defaultValue = $ids[0] } New-UDSelect -Id "ClientIDs" -ClassName "inputrequired" -DefaultValue $defaultValue -FullWidth -Option { foreach ($client in $clients) { if ($ids.Contains($client.GUID) -or $roles.Contains($PSU_GUI_AdminRole)) { New-UDSelectOption -Name $client.Name -Value $client.GUID } } } -OnChange { Sync-UDElement -Id 'ApplicationListTableData' } New-UDElement -tag "br" New-UDElement -tag "br" New-UDElement -Tag "div" -ClassName "container-fluid" -Content { New-UDElement -Tag "div" -ClassName "row justify-content-start" -Content { New-UDElement -Tag "div" -ClassName "col-5" -Content { New-UDElement -Tag "div" -ClassName "card-body rounded" -Content { New-UDTypography -Text "Application List" -Variant "h5" -ClassName "card-title rounded x-card-title" New-UDElement -Tag "div" -id "ApplicationList" -Content { New-UDDataGrid -id "ApplicationListTableData" -LoadRows { Initialize-AppFactoryProcess -ApplicationServicePath $AppFactory_ApplicationPath $tableData = [System.Collections.Generic.List[PSCustomObject]]@() $clientGUID = (Get-UDElement -id "ClientIDs").value $rawData = Get-AppFactoryApp -Active | Where-Object { [String]::IsNullOrWhiteSpace($_.SourceFiles.publishTo) -or (-not [String]::IsNullOrWhiteSpace($_.SourceFiles.publishTo) -and $_.SourceFiles.publishTo -contains $clientGUID) } foreach ($item in $rawData) { $AppDetails = Get-AppFactoryServiceClientAppConfig -orgGUID $clientGUID -appGUID $item.GUID if ([String]::IsNullOrWhiteSpace($AppDetails.AddToIntune)) { $AddToIntune = "False" } else { $AddToIntune = "True" } $obj = [PSCustomObject]@{ id = $item.GUID Name = $item.Information.DisplayName Enabled = $AddToIntune Updated = $item.SourceFiles.LastUpdate ClientDetails = ($AppDetails | ConvertTo-Json -Depth 5) InformationURL = $item.information.InformationURL PrivacyURL = $item.Information.PrivacyURL } $tableData.Add($obj) | Out-Null } $TableData | Out-UDDataGridData -Context $EventData -TotalRows $Rows.Length } -Columns @( New-UDDataGridColumn -Field ID -Flex 0 -DisableColumnMenu -DisableReorder -Hide New-UDDataGridColumn -Field Name -Flex 1.5 -Render { $EventData.Name New-UDElement -tag "div" -content {} -Attributes @{style = @{width = "10px" } } if ($null -ne $EventData.InformationURL -and $EventData.InformationURL -ne "") { New-UDLink -Url $EventData.InformationURL -OpenInNewWindow -Content { New-UDImage -URL "/assets/images/information.png" -Attributes @{ alt = "$($EventData.InformationURL)" style = @{ width = "20px" height = "20px" } } } } New-UDElement -tag "div" -content {} -Attributes @{style = @{width = "10px" } } if ($null -ne $EventData.PrivacyURL -and $EventData.PrivacyURL -ne "") { New-UDLink -Url $EventData.PrivacyURL -OpenInNewWindow -Content { New-UDImage -URL "/assets/images/privacy.png" -Attributes @{ alt = "$($EventData.PrivacyURL)" style = @{ width = "20px" height = "20px" } } } } } New-UDDataGridColumn -Field Enabled -Flex 1.5 New-UDDataGridColumn -Field Updated -Flex 1.5 New-UDDataGridColumn -Field ClientDetails -Flex 0 -DisableColumnMenu -DisableExport -DisableReorder -Hide -Render {} ) -StripedRows -AutoHeight $true -PageSize 10 -RowsPerPageOptions @(10, 25, 50, 100, 1000) -ShowPagination -DefaultSortColumn Name -OnSelectionChange { Import-Module -Name $AppFactory_Module -Force $TableData = Get-UDElement -Id "ApplicationListTableData" $selectedRow = ((Get-UDElement -Id "ApplicationListTableData").selection)[0] $selectedRowData = $TableData.Data.Rows | Where-Object { $_.ID -eq $selectedRow } $AppVersions = Get-AppFactoryServiceAppVersions -appGUID $selectedRow -AllAppList $script:PublishedAppList $AppDetails = $selectedRowData.ClientDetails | ConvertFrom-Json $PreviousVersionNumber = 0 if (-not [String]::IsNullOrWhiteSpace($AppDetails.KeepPrevious)) { $PreviousVersionNumber = $AppDetails.KeepPrevious } Set-UDElement -id "ApplicationGUID" -Attributes @{ "value" = $selectedRow } Set-UDElement -id "ApplicationName" -Attributes @{ "value" = $selectedRowData.Name } Set-UDElement -id "Enabled" -Attributes @{ "checked" = [System.Convert]::ToBoolean($selectedRowData.Enabled) } Set-UDElement -id "DownloadForground" -Attributes @{ "checked" = [System.Convert]::ToBoolean($AppDetails.foreground) } Set-UDElement -id "PreviousVersions" -Attributes @{ "value" = $PreviousVersionNumber } Set-UDElement -id "ESP" -Attributes @{ "value" = $AppDetails.espprofiles -join ", " } Set-UDElement -id "CopyPrevious" -Attributes @{ "checked" = [System.Convert]::ToBoolean($AppDetails.CopyPrevious) } Set-UDElement -id "RemovePrevious" -Attributes @{ "checked" = [System.Convert]::ToBoolean($AppDetails.UnassignPrevious) } Set-UDElement -id "InteractiveInstall" -Attributes @{ "checked" = [System.Convert]::ToBoolean($AppDetails.InteractiveInstall) } Set-UDElement -id "InteractiveUninstall" -Attributes @{ "checked" = [System.Convert]::ToBoolean($AppDetails.InteractiveUninstall) } Set-UDElement -id "Available_Install" -Attributes @{ "value" = $AppDetails.AvailableAssignments -join ", " } Set-UDElement -id "Available_Exceptions" -Attributes @{ "value" = $AppDetails.AvailableExceptions -join ", " } Set-UDElement -id "Required_Install" -Attributes @{ "value" = $AppDetails.RequiredAssignments -join ", " } Set-UDElement -id "Required_Exceptions" -Attributes @{ "value" = $AppDetails.RequiredExceptions -join ", " } Set-UDElement -id "Required_Uninstall" -Attributes @{ "value" = $AppDetails.UninstallAssignments -join ", " } Set-UDElement -id "Uninstall_Exceptions" -Attributes @{ "value" = $AppDetails.UninstallExceptions -join ", " } $FilterDetails = [System.Collections.Generic.List[String]]@() if ($appdetails.filters) { $FilterNames = ($appdetails.filters | get-member | where-Object { $_.MemberType -eq "NoteProperty" } | select-object Name).Name foreach ($filter in $FilterNames) { $FilterDetails.Add("$($filter);$($appdetails.filters.$filter.filterName);$($appdetails.filters.$filter.filterType)") } } Set-UDElement -id "FilterList" -Attributes @{ "value" = $FilterDetails -join ", " } if ([String]::IsNullOrWhiteSpace($AppDetails.AppVersion)) { $VersionValue = "0.0" } else { $VersionValue = $AppDetails.AppVersion } Set-UDElement -id "SelectedVersion" -Properties @{ Options = @( New-UDSelectOption -Name "Latest" -Value "0.0" foreach ($version in ($AppVersions | Sort-Object -Descending)) { New-UDSelectOption -Name $version -Value $version } ) DefaultValue = $VersionValue } Set-UDElement -id "UpdateApplication" -Properties @{ Disabled = $false } } } } } New-UDElement -Tag "div" -ClassName "col-1" -Content {} New-UDElement -Tag "div" -ClassName "col-6" -Content { New-UDElement -Tag "div" -ClassName "card-body rounded" -Content { New-UDTypography -Text "Application Details" -Variant "h5" -ClassName "card-title rounded x-card-title" New-UDButton -Id "UpdateApplication" -Text "Update Application" -ClassName "btn btn-primary" -Disabled -OnClick { Import-Module -Name $AppFactory_Module -Force Initialize-AppFactoryProcess -ApplicationServicePath $AppFactory_ApplicationPath $selectedRow = ((Get-UDElement -Id "ApplicationListTableData").selection)[0] $orgID = (Get-UDElement -id "ClientIDs").value $AppVersionSelected = (Get-UDElement -id "SelectedVersion").Value $AppConfig = @{ orgGUID = $orgID appGUID = $selectedRow AddToIntune = (Get-UDElement -id "Enabled").checked AvailableAssignments = ((Get-UDelement -id "Available_Install").Value -split ",") AvailableExceptions = ((Get-UDelement -id "Available_Exceptions").Value -split ",") RequiredAssignments = ((Get-UDelement -id "Required_Install").Value -split ",") RequiredExceptions = ((Get-UDelement -id "Required_Exceptions").Value -split ",") UninstallAssignments = ((Get-UDelement -id "Required_Uninstall").Value -split ",") UninstallExceptions = ((Get-UDelement -id "Uninstall_Exceptions").Value -split ",") UnassignPrevious = (Get-UDElement -id "RemovePrevious").checked CopyPrevious = (Get-UDElement -id "CopyPrevious").checked KeepPrevious = (Get-UDElement -id "PreviousVersions").Value foreground = (Get-UDElement -id "DownloadForground").checked espprofiles = ((Get-UDelement -id "ESP").Value -split ",") InteractiveInstall = (Get-UDElement -id "InteractiveInstall").checked InteractiveUninstall = (Get-UDElement -id "InteractiveUninstall").checked AppVersion = $AppVersionSelected } $AllFilters = (Get-UDElement -id "FilterList").Value -split "," $filters = @{} foreach ($filter in $AllFilters) { $filterDetails = $filter -split ";" if (-not [String]::IsNullOrWhiteSpace($filterDetails[0])) { $filters.Add($filterDetails[0], @{filterName = $filterDetails[1]; filterType = $filterDetails[2] }) } } $AppConfig.Add("filters", $filters) Set-AppFactoryServiceClientAppConfig @AppConfig Sync-UDElement -Id 'ApplicationListTableData' } New-UDElement -Tag "table" -Attributes @{ "style" = @{ "width" = "100%"; } "cellpadding" = "1" } -Content { New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "GUID:" -id "ApplicationGUID" -placeholder "" -disabled -item_colspan 3 -item_width 80 } New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Display Name:" -id "ApplicationName" -placeholder "" -disabled -item_colspan 3 -item_width 80 } New-UDElement -Tag "tr" -Content { New-PSUGUISwitch -Label "Enabled:" -id "Enabled" New-PSUGUISwitch -Label "Download Foreground:" -id "DownloadForground" } New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Keep Previous Versions:" -id "PreviousVersions" -placeholder "" New-PSUGUIInputSelectGroup -Label "Version:" -id "SelectedVersion" -placeholder "" -DefaultValue "" } New-UDElement -Tag "tr" -Content { New-PSUGUISwitch -Label "Copy Previous Assignments:" -id "CopyPrevious" New-PSUGUISwitch -Label "Unassign Previous Assignments:" -id "RemovePrevious" } New-UDElement -Tag "tr" -Content { New-PSUGUISwitch -Label "Interactive Install:" -id "InteractiveInstall" New-PSUGUISwitch -Label "Interactive Uninstall:" -id "InteractiveUninstall" } New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "ESP Assignments:" -id "ESP" -placeholder "Names of entra groups comma seperated" -item_colspan 3 -item_width 80 } New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Filters:" -id "FilterList" -placeholder "See docuemntation for proper format" -item_colspan 3 -item_width 80 } New-UDElement -Tag "tr" -content { New-UDElement -Tag 'td' -content { New-UDElement -Tag "br" -content {} } } New-UDElement -Tag "tr" -Content { New-UDElement -Tag "td" -Content { New-UDTypography -Text "Application Install Assignments" -Variant "h6" -ClassName "card-title rounded x-card-title" } -Attributes @{Colspan = 4 } } New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Availabe:" -id "Available_Install" -placeholder "Names of entra groups comma seperated" -item_colspan 3 -item_width 80 } New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Availabe Exceptions:" -id "Available_Exceptions" -placeholder "Names of entra groups comma seperated" -item_colspan 3 -item_width 80 } New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Required:" -id "Required_Install" -placeholder "Names of entra groups comma seperated" -item_colspan 3 -item_width 80 } New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Required Exceptions:" -id "Required_Exceptions" -placeholder "Names of entra groups comma seperated" -item_colspan 3 -item_width 80 } New-UDElement -Tag "tr" -content { New-UDElement -Tag 'td' -content { New-UDElement -Tag "br" -content {} } } New-UDElement -Tag "tr" -Content { New-UDElement -Tag "td" -Content { New-UDTypography -Text "Application Uninstall Assignments" -Variant "h6" -ClassName "card-title rounded x-card-title" } -Attributes @{Colspan = 4 } } New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Required:" -id "Required_Uninstall" -placeholder "Names of entra groups comma seperated" -item_colspan 3 -item_width 80 } New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Exceptions:" -id "Uninstall_Exceptions" -placeholder "Names of entra groups comma seperated" -item_colspan 3 -item_width 80 } } } New-UDElement -Tag "div" -id "ts_step" -content {} } } } } #EndRegion '.\Public\Get-AppfactoryPSUClientApplications.ps1' 255 #Region '.\Public\Get-AppfactoryPSUClients.ps1' 0 function Get-AppfactoryPSUClients { [cmdletbinding()] param() New-UDElement -Tag "figure" -ClassName "text-center" -Content { New-UDElement -Tag "h4" -ClassName "display-4" -Content { "Application Factory Clients" } } New-UDElement -Tag "div" -ClassName "container-fluid" -Content { New-UDElement -Tag "div" -ClassName "row justify-content-start" -Content { New-UDElement -Tag "div" -ClassName "col-7" -Content { New-UDElement -Tag "div" -ClassName "card-body rounded" -Content { New-UDTypography -Text "Client Lists" -Variant "h5" -ClassName "card-title rounded x-card-title" New-UDElement -Tag "div" -id "ClientList" -Content { New-UDDataGrid -id "ClientTableData" -LoadRows { Initialize-AppFactoryProcess -ApplicationServicePath $AppFactory_ApplicationPath Get-AppFactoryServiceClient | Select-Object -Property @{Label = "ID"; expression = { $_.GUID } }, Name, Contacts | Out-UDDataGridData -Context $EventData -TotalRows $Rows.Length } -Columns @( New-UDDataGridColumn -Field Name -Flex 1.5 New-UDDataGridColumn -Field Contacts -Flex 1.5 -Render { $EventData.Contacts -join ", " } ) -StripedRows -AutoHeight $true -PageSize 1000 -DefaultSortColumn Name -OnSelectionChange { $TableData = Get-UDElement -Id "ClientTableData" $selectedRow = ((Get-UDElement -Id "ClientTableData").selection)[0] $selectedRowData = $TableData.Data.Rows | Where-Object {$_.ID -eq $selectedRow} Set-UDElement -id "clientNameText" -Properties @{ Attributes = @{ value = $selectedRowData.Name type = "text" class = "form-control" classname = $null placeholder = "Client Name" } } Set-UDElement -id "contactListTextArea" -Properties @{ Tag = "textarea" Attributes = @{ value = ($selectedRowData.Contacts -join "`n") type = "text" class = "form-control" classname = $null rows = 4 placeholder = "Contact List. One per line." } } Set-UDElement -id "UpdateClient" -Properties @{ Disabled = $false } Set-UDElement -id "deleteClient" -Properties @{ Disabled = $false } } } } } New-UDElement -Tag "div" -ClassName "col-1" -Content {} New-UDElement -Tag "div" -ClassName "col-4" -Content { New-UDElement -Tag "div" -ClassName "card-body rounded" -Content { New-UDTypography -Text "Client Details" -Variant "h5" -ClassName "card-title rounded x-card-title" New-UDButton -Id "NewClient" -Text "New Client" -ClassName "btn btn-primary" -OnClick { $clientName = (Get-UDElement -id "clientNameText").Attributes.Value $contactList = (Get-UDElement -id "contactListTextArea").Attributes.Value -split "\n" if ([string]::IsNullOrEmpty($clientName)){ Show-UDToast -Message "Client Name is Required" -Duration 5000 -Position "topCenter" -BackgroundColor "#FF0000" return } New-AppFactoryServiceClient -clientName $clientName -clientContacts $contactList Sync-UDElement -Id 'ClientTableData' Set-UDElement -id "clientNameText" -Properties @{ Attributes = @{ value = "" type = "text" class = "form-control" classname = $null placeholder = "Client Name" } } Set-UDElement -id "contactListTextArea" -Properties @{ Attributes = @{ value = "" type = "text" class = "form-control" classname = $null rows = 4 placeholder = "Contact List. One per line." } } } New-UDButton -Id "UpdateClient" -Text "Update Client" -ClassName "btn btn-primary" -Disabled -OnClick { Show-UDModal -MaxWidth lg -Content { $clientName = (Get-UDElement -id "clientNameText").Attributes.Value New-UDTypography -Text "Are you sure you want to update this client? $($clientName)" -Variant "h5" New-UDButton -Text "Yes" -ClassName "btn btn-primary" -OnClick { $TableData = Get-UDElement -Id "ClientTableData" $selectedRow = ((Get-UDElement -Id "ClientTableData").selection)[0] $selectedRowData = $TableData.Data.Rows | Where-Object {$_.ID -eq $selectedRow} $clientName = (Get-UDElement -id "clientNameText").Attributes.Value $contactList = (Get-UDElement -id "contactListTextArea").Attributes.Value -split "\n" $params = @{ clientGUID = $selectedRow } $updated = $false if(($contactList -join ", ") -ne $selectedRowData.renderedcontacts){ $updated = $true $params.Add("clientContact",$contactList) } if($clientName -ne $selectedRowData.Name){ $updated = $true $params.Add("clientName",$clientName) } if($updated){ Set-AppFactoryServiceClient @params Sync-UDElement -Id 'ClientTableData' Hide-UDModal } } New-UDButton -Text "No" -ClassName "btn btn-primary" -OnClick { Hide-UDModal } } } New-UDButton -Id "deleteClient" -Text "Delete Client" -ClassName "btn btn-primary" -Disabled -OnClick { Show-UDModal -MaxWidth lg -Content { $clientName = (Get-UDElement -id "clientNameText").Attributes.Value New-UDTypography -Text "Are you sure you want to delete this client? $($clientName)" -Variant "h5" New-UDButton -Text "Yes" -ClassName "btn btn-primary" -OnClick { $clientGUID = ((Get-UDElement -Id "ClientTableData").selection)[0] Remove-AppFactoryServiceClient -clientGUID $clientGUID Sync-UDElement -Id 'ClientTableData' Set-UDElement -id "clientNameText" -Properties @{ Attributes = @{ value = "" type = "text" class = "form-control" classname = $null placeholder = "Client Name" } } Set-UDElement -id "contactListTextArea" -Properties @{ Attributes = @{ value = "" type = "text" class = "form-control" classname = $null rows = 4 placeholder = "Contact List. One per line." } } Hide-UDModal } New-UDButton -Text "No" -ClassName "btn btn-primary" -OnClick { Hide-UDModal } } } New-UDElement -Tag "div" -ClassName "mb-3" -Content { New-UDElement -Tag "label" -Attributes @{ for = "Client Name" class = "form-label" } -Content { "Client Name" } New-UDElement -Tag "input" -id "clientNameText" -Attributes @{ type = "text" class = "form-control" placeholder = "Client Name" } } New-UDElement -Tag "div" -ClassName "mb-3" -Content { New-UDElement -Tag "label" -Attributes @{ for = "Contact List" class = "form-label" } -Content { "Client List" } New-UDElement -Tag "textarea" -id "contactListTextArea" -Attributes @{ rows = "4" class = "form-control" placeholder = "Contact List. One per line." } } } } } } } <# New-UDApp -Content { $Rows = 1..100 | % { @{ Id = $_; Name = 'Adam'; Number = Get-Random} } New-UDDataGrid -id DataGrid -LoadRows { $Rows| Out-UDDataGridData -Context $EventData -TotalRows $Rows.Length } -Columns @( New-UDDataGridColumn -Field name New-UDDataGridColumn -Field number ) -AutoHeight $true -Pagination -CheckboxSelection -CheckboxSelectionVisibleOnly -DisableRowSelectionOnClick #> #EndRegion '.\Public\Get-AppfactoryPSUClients.ps1' 196 #Region '.\Public\Get-AppFactoryServiceAppVersions.ps1' 0 function Get-AppFactoryServiceAppVersions{ [CmdletBinding()] [OutputType([System.Collections.Generic.List[Version]])] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$appGUID, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][PSCustomObject[]]$AllAppList, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) $AppList = (($AllAppList | Select-Object -Property Values).Values).Name | Sort-Object -Unique | Where-Object { $_ -like "$($appGUID)/*/App.json" } if (-not [String]::IsNullOrWhiteSpace($AppList)) { [System.Collections.Generic.List[Version]]$AppVersions = ([regex]::Matches($AppList , "/(.*?)/App.json")).Groups.Value | Where-Object { $_ -notlike "*App.json" } } return $AppVersions } #EndRegion '.\Public\Get-AppFactoryServiceAppVersions.ps1' 15 #Region '.\Public\Get-AppFactoryServiceClient.ps1' 0 <# .DESCRIPTION This cmdlet is designed to list out the clients that are configured .PARAMETER GUID The unique identifer for the specific client .PARAMETER Name Get an client based on the name .PARAMETER Contact Get clients that have a specific contact .PARAMETER LogLevel If logging is enabled, what level of logging do we want, default is verbose. .EXAMPLE Get all client Get-AppFactoryClient Get specific client by clientGUID Get-AppFactoryClient -clientGUID "### GUID ###" Get specific client by clientName Get-AppFactoryClient -clientName "### client Name ###" Get specific client by Contact Get-AppFactoryClient -clientContact "### Contact Name ###" #> function Get-AppFactoryServiceClient { [CmdletBinding()] [Alias("Get-AppFactoryOrganization")] [OutputType([System.Collections.Generic.List[PSCustomObject]])] param( [Alias("GUID")][Parameter()][ValidateNotNullOrEmpty()][string]$clientGUID, [Alias("Name")][Parameter()][ValidateNotNullOrEmpty()][string]$clientName, [Alias("Contact")][Parameter()][ValidateNotNullOrEmpty()][string]$clientContact, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) # Client Configuration Folder $clientsFolder = Join-Path -Path $script:AppFactorySourceDir -ChildPath "Clients" if ($script:AppFactoryLogging) { Write-PSFMessage -Message "Reading client files in path <c='green'>$($clientsFolder)</c>" -Level $LogLevel -Tag "Clients" -Target "Application Factory Service" } # Get list of client configuration files $clientConfigs = Get-Childitem -Path $clientsFolder # Create list that we will return with the clients configurations $clients = [System.Collections.Generic.List[PSCustomObject]]@() foreach ($file in $clientConfigs) { # Read the clients file $json = Get-Content $file.FullName | ConvertFrom-Json if ($PSBoundParameters.ContainsKey("clientGUID") -and $json.GUID -ne $clientGUID) { continue } # If Name is set, match the name variable. if ($PSBoundParameters.ContainsKey("clientName") -and $json.Name -notlike "$($clientName)") { continue } # If Contact is set, match entries that have that contact if ($PSBoundParameters.ContainsKey("clientContact") -and $Json.Contacts.indexOf($clientContact) -eq -1) { continue } if ($script:AppFactoryLogging) { Write-PSFMessage -Message "Reading client file <c='green'>$($file)</c>" -Level $LogLevel -Tag "Clients", "$($json.Name)" -Target "Application Factory Service" } # Add the path to the file for specific client $json | Add-Member -MemberType "NoteProperty" -Name "FileName" -Value $file.Name $clients.Add($json) | Out-Null } # Return the clients list return $clients } #EndRegion '.\Public\Get-AppFactoryServiceClient.ps1' 63 #Region '.\Public\Get-AppFactoryServiceClientApp.ps1' 0 function Get-AppFactoryServiceClientApp{ [CmdletBinding()] [OutputType([System.Collections.Generic.List[PSCustomObject]])] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$orgGUID, [Parameter()][ValidateNotNullOrEmpty()][string]$appGUID, [Parameter()][switch]$AddToIntune, [Parameter()][ValidateSet("Output","Verbose")][string]$LogLevel = "Verbose" ) # Blank List for the Apps $applicaitonList = [System.Collections.Generic.List[PSCustomObject]]@() # Where are custom configs stored $ClientConfigFolderPath = Join-Path -Path $script:AppFactoryClientConfigDir -ChildPath "$($orgGUID)" # Public application list $publicApps = Get-AppFactoryApp -active -public -LogLevel $LogLevel # Client specific application list $clientApps = Get-AppFactoryApp -active -publishTo $orgGUID -LogLevel $LogLevel # Loop through each public app foreach($app in $publicApps){ $customConfigPath = Join-Path -Path $ClientConfigFolderPath -ChildPath "$($app.GUID).json" $customConfig = $null if(Test-Path -Path $customConfigPath){ $customConfig = Get-Content -Path $customConfigPath | ConvertFrom-Json -Depth 5 } $AppConfig = Get-ClientAppConfig -application $app -customConfig $customConfig -audience "Public" -LogLevel $LogLevel if($AddToIntune.IsPresent -and -not $AppConfig.AddToIntune){ continue } $applicaitonList.Add($AppConfig) } foreach($app in $clientApps){ $customConfigPath = Join-Path -Path $ClientConfigFolderPath -ChildPath "$($app.GUID).json" $customConfig = $null if(Test-Path -Path $customConfigPath){ $customConfig = Get-Content -Path $customConfigPath | ConvertFrom-Json -Depth 5 } $AppConfig = Get-ClientAppConfig -application $app -customConfig $customConfig -audience $orgGUID -LogLevel $LogLevel if($AddToIntune.IsPresent -and -not $AppConfig.AddToIntune){ continue } $applicaitonList.Add($AppConfig) } return $applicaitonList } #EndRegion '.\Public\Get-AppFactoryServiceClientApp.ps1' 45 #Region '.\Public\Get-AppFactoryServiceClientAppConfig.ps1' 0 function Get-AppFactoryServiceClientAppConfig{ [CmdletBinding()] [OutputType([System.Collections.Generic.List[PSCustomObject]])] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$orgGUID, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$appGUID, [Parameter()][ValidateSet("Output","Verbose")][string]$LogLevel = "Verbose" ) $appConfigPath = Join-Path -Path $script:AppFactoryClientConfigDir -ChildPath "$($orgGUID)\$($appGUID).json" if(-not (Test-Path $appConfigPath)){ return $false } return (Get-Content -Path $appConfigPath | ConvertFrom-JSON) } #EndRegion '.\Public\Get-AppFactoryServiceClientAppConfig.ps1' 15 #Region '.\Public\Get-AppFactoryStorageSAS.ps1' 0 function Get-AppFactoryStorageSAS{ [CmdletBinding()] [OutputType([Hashtable])] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$GUID, [Parameter()][ValidateNotNullOrEmpty()][int]$hours = 2, [Parameter()][ValidateSet("Output","Verbose")][string]$LogLevel = "Verbose" ) # Create expiry time $SASExpiry = (Get-Date).ToUniversalTime().AddHours($hours) # Azure Storage Contexts. $script:psadtStorageContext = Connect-AppFactoryAzureStorage -storageContainer $script:AppFactoryDeploymentsContainer -storageSecret $script:AppFactoryDeploymentsSecret -LogLevel $LogLevel # Store the details for the connectivity and return it try{ $SASTokens = @{ "StoragePath" = "https://$($script:AppFactoryDeploymentsContainer).blob.core.windows.net" "PublicContainerName" = $script:AppFactoryPublicFolder "OrganizationContainerName" = $GUID "public" = New-AzStorageContainerSASToken -Context $script:psadtStorageContext -Name $script:AppFactoryPublicFolder -Permission r -ExpiryTime $SASExpiry "organization" = New-AzStorageContainerSASToken -Context $script:psadtStorageContext -Name $GUID -Permission r -ExpiryTime $SASExpiry } if ($script:AppFactoryLogging) { Write-PSFMessage -Message "Created SAS Tokens for client with GUID <c='green'>$($GUID)</c>" -Level $LogLevel -Tag "Azure","Storage","SAS" -Target "Application Factory Service" } return $SASTokens } catch{ if ($script:AppFactoryLogging) { Write-PSFMessage -Message "Unable to creat SAS Tokens for client with GUID <c='green'>$($GUID)</c>" -Level "Error" -Tag "Azure","Storage","SAS" -Target "Application Factory Service" } throw $_ } } #EndRegion '.\Public\Get-AppFactoryStorageSAS.ps1' 34 #Region '.\Public\Get-NewlyPublishedApplications.ps1' 0 function Get-NewlyPublishedApplications { [CmdletBinding()] param( [Parameter()][datetime]$startDate = ((Get-Date).AddDays(-1)), [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) # Connect to get graph token Get-GraphAccessToken -clientID $script:AppFactoryServiceClientID -tenantID $script:AppFactoryServiceTenantID -clientSecret (ConvertFrom-SecureString -SecureString $script:AppFactoryServiceSecret -AsPlainText) | Out-Null # Get the list of applications $UpdatedApplications = Get-AppFactoryApp -LogLevel $LogLevel | Where-Object { $null -ne $_.SourceFiles.LastUpdate -and $_.SourceFiles.LastUpdate -ne "" -and (Get-Date -Date $_.SourceFiles.LastUpdate) -ge $startDate } $Clients = Get-AppFactoryServiceClient -LogLevel $LogLevel foreach($client in $clients){ $emailbody = [System.Collections.Generic.List[String]]::new() $emailBody.add("<html>") $emailBody.add(" <body>") $emailBody.add(" <h1>Newly Published Applications - Public</h1>") $emailBody.add(" <table style='width: 100%;'>") $emailBody.add(" <tr>") $emailbody.Add(" <th style='width: 33%;background-color:#c0c0c0;border:1px solid black;'>Application</th>") $emailbody.Add(" <th style='width: 33%;background-color:#c0c0c0;border:1px solid black;'>Version</th>") $emailbody.Add(" <th style='width: 33%;background-color:#c0c0c0;border:1px solid black;'>Updated</th>") $emailbody.Add(" </tr>") foreach($app in ($UpdatedApplications | Where-Object {-not $_.SourceFiles.publishTo})){ $emailBody.add(" <tr>") $emailBody.Add(" <td>$($app.Information.DisplayName)</td>") $emailBody.Add(" <td>$($app.Information.AppVersion)</td>") $emailBody.Add(" <td>$($app.SourceFiles.LastUpdate)</td>") $emailBody.add(" </tr>") } $emailBody.add(" </table>") $emailBody.add(" <h1>Newly Published Applications - $($client.Name)</h1>") $emailBody.add(" <table style='width: 100%;'>") $emailBody.add(" <tr>") $emailbody.Add(" <th style='width: 33%;background-color:#c0c0c0;border:1px solid black;'>Application</th>") $emailbody.Add(" <th style='width: 33%;background-color:#c0c0c0;border:1px solid black;'>Version</th>") $emailbody.Add(" <th style='width: 33%;background-color:#c0c0c0;border:1px solid black;'>Updated</th>") $emailbody.Add(" </tr>") foreach($app in ($UpdatedApplications | Where-Object {$_.SourceFiles.publishTo})){ if($client.guid -in $app.SourceFiles.publishTo){ $emailBody.add(" <tr>") $emailBody.Add(" <td>$($app.Information.DisplayName)</td>") $emailBody.Add(" <td>$($app.Information.AppVersion)</td>") $emailBody.Add(" <td>$($app.SourceFiles.LastUpdate)</td>") $emailBody.add(" </tr>") } } $emailBody.add(" </table>") $emailBody.add(" </body>") $emailBody.add("</html>") if($client.Contacts){ $params = @{ from = $script:AppFactoryServiceSendMailAs subject = "Newly Published Applications" to = $clients.Contacts message = $emailbody } Send-GraphMailMessage @params } } #$UpdatedApplications.Information.DisplayName } #EndRegion '.\Public\Get-NewlyPublishedApplications.ps1' 67 #Region '.\Public\Get-PSUGuiAppDetectionInfo.ps1' 0 function Get-PSUGuiAppDetectionInfo{ [cmdletbinding()] [OutputType([System.Collections.Generic.List[Hashtable]])] param( ) $AppDetection = @{} $UninstallInformationMap = @( @{ id = "Detection_VersionCompare" param = "ProductVersionOperator" type = "text" }, @{ id = "Detection_Script_32bit" param = "RunAs32Bit" type = "switch" }, @{ id = "Detection_Keypath" param = "KeyPath" type = "text" }, @{ id = "Detection_Item" param = "ValueName" type = "text" }, @{ id = "Detection_Operator" param = "Operator" type = "text" }, @{ id = "Detection_32bit" param = "Check32BitOn64System" type = "switch" } ) $AppDetectionName = (Get-UDElement -id "Detection").Value if ([String]::IsNullOrWhiteSpace($AppDetectionName)) { Show-UDToast -Message "Application Detection is required on the detection tab." -Duration 3000 -Position "topCenter" -BackgroundColor "#FF0000" $global:submitApp = $false } else{ if($AppDetectionName -eq "Registry Version"){ $AppDetection.Add("Type", "Registry") | Out-Null $AppDetection.Add("DetectionMethod", "VersionComparison") | Out-Null } elseif($AppDetectionName -eq "Registry Existance"){ $AppDetection.Add("Type", "Registry") | Out-Null $AppDetection.Add("DetectionMethod", "Existence") | Out-Null } else{ $AppDetection.Add("Type", $AppDetectionName) | Out-Null } foreach ($item in $UninstallInformationMap) { $data = Get-UDElement -id $item.ID if ($item.type -eq "switch" -and $null -ne $data.checked) { $AppDetection.Add($item.param, $data.checked) | Out-Null } else{ if (-not [String]::IsNullOrWhiteSpace($data.value)) { $AppDetection.Add($item.param, $data.value) | Out-Null } } } } return $AppDetection } #EndRegion '.\Public\Get-PSUGuiAppDetectionInfo.ps1' 70 #Region '.\Public\Get-PSUGUIAppInfo.ps1' 0 function Get-PSUGUIAppInfo { [cmdletbinding()] [OutputType([System.Collections.Generic.List[Hashtable]])] param( ) $AppInformation = @{} $FilterInformation = @{} $InformationFieldMap = @( @{ id = "ApplicationName" param = "displayName" required = $true type = "text" }, @{ id = "Publisher" param = "publisher" required = $true type = "text" }, @{ id = "Owner" param = "owner" required = $false type = "text" }, @{ id = "Active" param = "Active" required = $false type = "switch" }, @{ id = "pauseUpdate" param = "pauseUpdate" required = $false type = "switch" }, @{ id = "InstallExperience" param = "InstallExperience" required = $false type = "select" }, @{ id = "Client" param = "publishTo" required = $false type = "select_client" }, @{ id = "informationURL" param = "informationURL" required = $false type = "text" }, @{ id = "PrivacyURL" param = "privacyURL" required = $false type = "text" }, @{ id = "Architecture" param = "Architecture" required = $false type = "select" }, @{ id = "MinimumSupportedWindowsRelease" param = "MinimumSupportedWindowsRelease" required = $false type = "select" }, @{ id = "Description" param = "Description" required = $true type = "text" }, @{ id = "Notes" param = "Notes" required = $false type = "text" } ) $SourceInformatinMap = @( @{ id = "StorageContainer" param = "StorageAccountContainerName" required = $true required_for = @("storageAccount", "Sharepoint", "LocalStorage") type = "text" }, @{ id = "Installer" param = "AppSetupFileName" required = $true required_for = @("storageAccount", "Sharepoint", "Winget", "Evergreen", "LocalStorage") type = "text" }, @{ id = "AppID" param = "AppID" required = $true required_for = @("Winget", "Evergreen") type = "text" }, @{ id = "AppVersion" param = "AppVersion" required = $true required_for = @("PSADT","PowerShell") type = "text" } ) $FilterInformationMap = @( @{ id = "Filter_Architecture" param = "architecture" }, @{ id = "Filter_Platform" param = "Platform" }, @{ id = "Filter_Channel" param = "Channel" }, @{ id = "Filter_Type" param = "Type" }, @{ id = "Filter_Release" param = "Release" }, @{ id = "Filter_Language" param = "Language" }, @{ id = "Filter_ImageType" param = "ImageType" } ) foreach ($item in $InformationFieldMap) { $data = Get-UDElement -id $item.id if ([String]::IsNullOrWhiteSpace($data.value) -and $item.required) { Show-UDToast -Message "$($item.id) is required on the Information tab." -Duration 3000 -Position "topCenter" -BackgroundColor "#FF0000" $global:submitApp = $false } else { if ($item.type -eq "switch" -and $null -ne $data.checked) { $AppInformation.Add($item.param, $data.checked) | Out-Null } elseif($item.type -eq "select_client"){ $Clients = [System.Collections.Generic.List[String]]::new() if($data.value){ $clientList = Get-AppFactoryServiceClient foreach($obj in $data.value){ $client = $clientList | Where-Object {$_.Name -eq $obj} $Clients.Add($client.GUID) } } $AppInformation.Add($item.param, $Clients) | Out-Null } else { if (-not [String]::IsNullOrWhiteSpace($data.value)) { $AppInformation.Add($item.param, $data.value) | Out-Null } } } } $AppSourceName = (Get-UDElement -id "Source").Value if ([String]::IsNullOrWhiteSpace($AppSourceName)) { Show-UDToast -Message "Application Source is required on the source tab." -Duration 3000 -Position "topCenter" -BackgroundColor "#FF0000" $global:submitApp = $false } else { $AppInformation.Add("AppSource", $AppSourceName) | Out-Null foreach ($item in $SourceInformatinMap) { $data = Get-UDElement -id $item.ID if ([String]::IsNullOrWhiteSpace($data.value) -and $item.required -and ($AppInformation.AppSource -in $item.required_for)) { Show-UDToast -Message "$($item.id) is required on the source tab." -Duration 3000 -Position "topCenter" -BackgroundColor "#FF0000" $global:submitApp = $false } else { if ($item.type -eq "switch" -and $null -ne $data.checked) { $AppInformation.Add($item.param, $data.checked) | Out-Null } else { if (-not [String]::IsNullOrWhiteSpace($data.value)) { $AppInformation.Add($item.param, $data.value) | Out-Null } } } } if ($AppSourceName -eq "Evergreen") { foreach ($item in $FilterInformationMap) { $data = Get-UDElement -id $item.id if (-not [String]::IsNullOrWhiteSpace($data.value)) { $FilterInformation.Add($item.param, $data.value) | Out-Null } } $AppInformation.Add("filterOptions", $FilterInformation) | Out-Null } } return $AppInformation } #EndRegion '.\Public\Get-PSUGUIAppInfo.ps1' 212 #Region '.\Public\Get-PSUGUIAppInstallInfo.ps1' 0 function Get-PSUGUIAppInstallInfo{ [cmdletbinding()] [OutputType([System.Collections.Generic.List[Hashtable]])] param( ) $AppInstall = @{} $InstallInformationMap = @( @{ id = "Install_installer" param = "installer" type = "text" }, @{ id = "Install_argumentList" param = "argumentList" type = "text" }, @{ id = "Install_conflictingProcessStart" param = "conflictingProcessStart" type = "array" }, @{ id = "Install_conflictingProcessEnd" param = "conflictingProcessEnd" type = "array" }, @{ id = "Install_ignoreExitCodes" param = "ignoreExitCodes" type = "array" }, @{ id = "Install_WIM" param = "wim" type = "switch" }, @{ id = "Install_secureArgumentList" param = "secureArgumentList" type = "switch" }, @{ id = "Install_transforms" param = "transforms" type = "text" }, @{ id = "Install_additionalArgumentList" param = "additionalArgumentList" type = "text" }, @{ id = "Install_SkipMSIAlreadyInstalledCheck" param = "SkipMSIAlreadyInstalledCheck" type = "switch" }, @{ id = "Install_Script" param = "script" type = "code" } ) $AppInstallName = (Get-UDElement -id "Install").Value if ([String]::IsNullOrWhiteSpace($AppInstallName)) { Show-UDToast -Message "Application Install is required on the install tab." -Duration 3000 -Position "topCenter" -BackgroundColor "#FF0000" $global:submitApp = $false } else{ $AppInstall.Add("Type", $AppInstallName) | Out-Null foreach ($item in $InstallInformationMap) { $data = Get-UDElement -id $item.ID if ($item.type -eq "switch" -and $null -ne $data.checked) { $AppInstall.Add($item.param, $data.checked) | Out-Null } elseif($item.type -eq "array" -and (-not [String]::IsNullOrWhiteSpace($data.value))){ $AppInstall.Add($item.param, ($data.value -split ",")) | Out-Null } elseif($item.type -eq "code" -and (-not [String]::IsNullOrWhiteSpace($data.code))){ $AppInstall.Add($item.param, ($data.code -split "`r`n")) | Out-Null } else{ if (-not [String]::IsNullOrWhiteSpace($data.value)) { $AppInstall.Add($item.param, $data.value) | Out-Null } } } } return $AppInstall } #EndRegion '.\Public\Get-PSUGUIAppInstallInfo.ps1' 91 #Region '.\Public\Get-PSUGUIAppUninstallInfo.ps1' 0 function Get-PSUGUIAppUninstallInfo { [cmdletbinding()] [OutputType([System.Collections.Generic.List[Hashtable]])] param( ) $AppUninstall = @{} $UninstallInformationMap = @( @{ id = "Uninstall_installer" param = "installer" type = "text" }, @{ id = "Uninstall_argumentList" param = "argumentList" type = "text" }, @{ id = "Uninstall_conflictingProcessStart" param = "conflictingProcessStart" type = "array" }, @{ id = "Uninstall_conflictingProcessEnd" param = "conflictingProcessEnd" type = "array" }, @{ id = "Uninstall_ignoreExitCodes" param = "ignoreExitCodes" type = "array" }, @{ id = "Uninstall_wim" param = "wim" type = "switch" }, @{ id = "Uninstall_dirFiles" param = "dirFiles" type = "switch" }, @{ id = "Uninstall_secureArgumentList" param = "secureArgumentList" type = "switch" }, @{ id = "Uninstall_productCode" param = "productCode" type = "text" }, @{ id = "Uninstall_additionalArgumentList" param = "additionalArgumentList" type = "text" }, @{ id = "Uninstall_name" param = "name" type = "text" }, @{ id = "Uninstall_Script" param = "script" type = "code" } ) $AppUninstallName = (Get-UDElement -id "Uninstall").Value if ([String]::IsNullOrWhiteSpace($AppUninstallName)) { Show-UDToast -Message "Application Uninstall is required on the uninstall tab." -Duration 3000 -Position "topCenter" -BackgroundColor "#FF0000" $global:submitApp = $false } else{ $AppUninstall.Add("Type", $AppUninstallName) | Out-Null foreach ($item in $UninstallInformationMap) { $data = Get-UDElement -id $item.ID if ($item.type -eq "switch" -and $null -ne $data.checked) { $AppUninstall.Add($item.param, $data.checked) | Out-Null } elseif($item.type -eq "array" -and (-not [String]::IsNullOrWhiteSpace($data.value))){ $AppUninstall.Add($item.param, ($data.value -split ",")) | Out-Null } elseif($item.type -eq "code" -and (-not [String]::IsNullOrWhiteSpace($data.code))){ $AppUninstall.Add($item.param, ($data.code -split "`r`n")) | Out-Null } else{ if (-not [String]::IsNullOrWhiteSpace($data.value)) { $AppUninstall.Add($item.param, $data.value) | Out-Null } } } } return $AppUninstall } #EndRegion '.\Public\Get-PSUGUIAppUninstallInfo.ps1' 96 #Region '.\Public\Import-AppFactoryECNOApp.ps1' 0 function Import-AppFactoryECNOApp { [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$applicationName, [Parameter()][String[]]$publishTo = @(), [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) # First download the application from sharepoint so that we can inspect it $application = [PSCustomObject]@{ "Information" = [PSCustomObject]@{ "DisplayName" = $applicationName } "SourceFiles" = [PSCustomObject]@{ "StorageAccountContainerName" = $applicationName } } $details = Get-AppFactoryECNOAppItem -application $application -LogLevel $LogLevel $AppSetupFolderPath = Join-Path -Path $script:AppFactoryWorkspace -ChildPath "Installers" -AdditionalChildPath $applicationName # Create path if it doesn't exist if (-not(Test-Path -Path $AppSetupFolderPath -PathType "Container")) { try { New-Item -Path $AppSetupFolderPath -ItemType "Container" -ErrorAction "Stop" | Out-Null } catch [System.Exception] { throw "[$($application.Information.DisplayName)] Failed to create '$($Path)' with error message: $($_.Exception.Message)" } } $Application.SourceFiles | Add-Member -MemberType NoteProperty -Name "PackageVersion" -Value $details.Version -Force $Application.SourceFiles | Add-Member -MemberType NoteProperty -Name "PackageSource" -Value $details.URI -Force Get-AppFactoryECNOFile -application $application -Destination $AppSetupFolderPath -LogLevel $LogLevel # Read the config file to get details $configFile = Join-Path -Path $AppSetupFolderPath -ChildPath "_win32app.txt" $file = Get-Content -Path $configFile $publisherName = $file[45].trim() $informationURL = $file[53].trim() $privacyURL = $file[55].trim() $Description = $file[43].trim() $Notes = $file[61].trim() # Create application cinfig $NewApplication = @{ displayName = $applicationName publisher = $publisherName description = $Description notes = $Notes owner = "ECNO" AppSource = "ECNO" StorageAccountContainerName = $applicationName informationURL = $informationURL PrivacyURL = $privacyURL publishTo = $publishTo } $NewApplication = New-AppFactoryApp @NewApplication $Detection = @{ appGUID = $NewApplication.GUID Type = "Script" } Set-AppFactoryAppDetectionRule @Detection $Install = @{ appGUID = $NewApplication.GUID Type = "ECNO" } Set-AppFactoryAppInstall @Install Set-AppFactoryAppUninstall @Install $iconFolder = Join-Path -Path $AppSetupFolderPath -ChildPath "osi" $icon = Get-ChildItem -Path $iconFolder -Filter "*.png" -Recurse $scriptFile = Join-Path -Path $AppSetupFolderPath -ChildPath "_detect.ps1" $appDestination = Join-Path -Path $script:AppFactorySourceDir -ChildPath "Apps" -AdditionalChildPath $applicationName Remove-Item -Path "$($appDestination)\detection.ps1" -Force Remove-Item -Path "$($appDestination)\Icon.png" -Force Copy-Item -Path $icon.FullName -Destination $appDestination -Force Copy-Item -Path $scriptFile -Destination $appDestination -Force Rename-Item -Path "$($appDestination)\$($icon.Name)" -NewName "Icon.png" -Force Rename-Item -Path "$($appDestination)\_detect.ps1" -NewName "detection.ps1" -Force Remove-Item -Path $AppSetupFolderPath -Recurse -Force -Confirm:$false } #EndRegion '.\Public\Import-AppFactoryECNOApp.ps1' 76 #Region '.\Public\Import-PreviousVersion.ps1' 0 function Import-PreviousVersion { [cmdletbinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$AppDetailsPath ) $test = $false $ApplicationData = Get-Content -Path $AppDetailsPath | ConvertFrom-JSON -Depth 10 #region Application Data $App = @{ displayName = ($ApplicationData.AppData.IntuneAppName -replace "STS-") publisher = $ApplicationData.AppData.AppPublisher description = $ApplicationData.AppConfig.Information.description owner = "ECNO" AppSource = $ApplicationData.AppData.AppSource informationURL = $ApplicationData.AppData.informationURL PrivacyURL = $ApplicationData.AppData.PrivacyURL publishTo = $ApplicationData.AppData.publishTo } switch ($ApplicationData.AppData.AppSource) { "Evergreen" { $App.Add("appID", $ApplicationData.AppData.appID) $App.Add("appSetupName", $ApplicationData.AppData.AppSetupFileName) $App.Add("filterOptions", $ApplicationData.AppData.filterOptions) } "StorageAccount" { $App.Add("StorageAccountContainerName", $ApplicationData.AppData.StorageAccountContainerName) $App.Add("appSetupName", $ApplicationData.AppData.AppSetupFileName) } "ECNO" { $App.Add("StorageAccountContainerName", $ApplicationData.AppData.StorageAccountContainerName) } "Winget" { $App.Add("appID", $ApplicationData.AppData.appID) $App.Add("appSetupName", $ApplicationData.AppData.AppSetupFileName) } } if(-not $test){ $application = New-AppFactoryApp @App } else{ "#################### APP ########################" $App } #endregion #region Install Data $install = @{ type = $ApplicationData.Install.type appGUID = $application.GUID } foreach ($member in ($ApplicationData.Install | get-member | where-object { $_.MemberType -eq "NoteProperty" })) { switch ($member.Name) { "afterstopProcess" { if(-not [String]::IsNullOrWhiteSpace($ApplicationData.Install.afterstopProcess)){ $install.Add("conflictingProcessEnd", $ApplicationData.Install.afterstopProcess) } } "beginstopProcess" { if(-not [String]::IsNullOrWhiteSpace($ApplicationData.Install.beginstopProcess)){ $install.Add("conflictingProcessStart", $ApplicationData.Install.beginstopProcess) } } "ignoreExit" { if(-not [String]::IsNullOrWhiteSpace($ApplicationData.Install.ignoreExit)){ $install.Add("ignoreExitCodes", $ApplicationData.Install.ignoreExit) } } "installer" { if((-not ([String]::IsNullOrWhiteSpace($ApplicationData.Install.installer)) -and $ApplicationData.Install.installer -ne "###SETUPFILENAME###")){ $install.Add("installer", $ApplicationData.Install.installer) } } "mst" { if(-not [String]::IsNullOrWhiteSpace($ApplicationData.Install.mst)){ $install.Add("transforms", $ApplicationData.Install.mst) } } "Parameters" { if(-not [String]::IsNullOrWhiteSpace($ApplicationData.Install.Parameters)){ if ($ApplicationData.Install.type -eq "MSI") { $install.Add("additionalArgumentList", $ApplicationData.Install.Parameters) } else{ $install.Add("argumentList", $ApplicationData.Install.Parameters) } } } "script" { if(-not [String]::IsNullOrWhiteSpace($ApplicationData.Install.script)){ $install.type = "Script" $install.Add("script", $ApplicationData.Install.script) } } "WIM" { if([bool]$ApplicationData.Install.WIM){ $Install.Add("WIM", $true) } } } } if(-not $test){ Set-AppFactoryAppInstall @Install } else{ "#################### INSTALL ########################" $ApplicationData.Install | get-member | where-object { $_.MemberType -eq "NoteProperty" } | format-table $Install } #endregion #region Uninstall Data $uninstall = @{ type = $ApplicationData.uninstall.type appGUID = $application.GUID } foreach ($member in ($ApplicationData.unInstall | get-member | where-object { $_.MemberType -eq "NoteProperty" })) { switch ($member.Name) { "afterstopProcess" { if(-not [String]::IsNullOrWhiteSpace($ApplicationData.unInstall.afterstopProcess)){ $unInstall.Add("conflictingProcessEnd", $ApplicationData.unInstall.afterstopProcess) } } "beginstopProcess" { if(-not [String]::IsNullOrWhiteSpace($ApplicationData.unInstall.beginstopProcess)){ $unInstall.Add("conflictingProcessStart", $ApplicationData.unInstall.beginstopProcess) } } "DirFiles" { if([bool]$ApplicationData.unInstall.DirFiles){ $unInstall.Add("DirFiles", $true) } } "ignoreExit" { if(-not [String]::IsNullOrWhiteSpace($ApplicationData.unInstall.ignoreExit)){ $unInstall.Add("ignoreExitCodes", $ApplicationData.unInstall.ignoreExit) } } "installer" { if(-not ([String]::IsNullOrWhiteSpace($ApplicationData.unInstall.installer) -and $ApplicationData.unInstall.installer -ne "###SETUPFILENAME###")){ $unInstall.Add("installer", $ApplicationData.unInstall.installer) } } "MSIGUID" { if(-not [String]::IsNullOrWhiteSpace($ApplicationData.unInstall.MSIGUID)){ $unInstall.Add("productCode", $ApplicationData.unInstall.MSIGUID) } } "Name" { if(-not [String]::IsNullOrWhiteSpace($ApplicationData.unInstall.Name)){ $unInstall.Add("Name", $ApplicationData.unInstall.Name) } } "Parameters" { if(-not [String]::IsNullOrWhiteSpace($ApplicationData.unInstall.Parameters)){ if ($ApplicationData.unInstall.type -eq "MSI") { $unInstall.Add("additionalArgumentList", $ApplicationData.unInstall.Parameters) } else{ $unInstall.Add("argumentList", $ApplicationData.unInstall.Parameters) } } } "script" { if(-not [String]::IsNullOrWhiteSpace($ApplicationData.unInstall.script)){ $unInstall.type = "Script" $unInstall.Add("script", $ApplicationData.unInstall.script) } } "WIM" { if([bool]$ApplicationData.unInstall.WIM){ $unInstall.Add("WIM", $true) } } } } if(-not $test){ Set-AppFactoryAppUninstall @Uninstall } else{ "#################### UNINSTALL ########################" $ApplicationData.unInstall | get-member | where-object { $_.MemberType -eq "NoteProperty" } | format-table $Uninstall } #endregion #region Detection Data $detection = @{ type = $ApplicationData.AppConfig.DetectionRule.type appGUID = $application.GUID } foreach ($member in ($ApplicationData.AppConfig.DetectionRule | get-member | where-object { $_.MemberType -eq "NoteProperty" })) { switch ($member.Name) { "Name" { if(-not [String]::IsNullOrWhiteSpace($ApplicationData.AppConfig.DetectionRule.Check32BitOn64System)){ $detection.Add("Check32BitOn64System", $ApplicationData.AppConfig.DetectionRule.Check32BitOn64System) } } "DetectionMethod" { if(-not [String]::IsNullOrWhiteSpace($ApplicationData.AppConfig.DetectionRule.DetectionMethod)){ $detection.Add("DetectionMethod", $ApplicationData.AppConfig.DetectionRule.DetectionMethod) } } "KeyPath" { if(-not [String]::IsNullOrWhiteSpace($ApplicationData.AppConfig.DetectionRule.KeyPath)){ $detection.Add("KeyPath", $ApplicationData.AppConfig.DetectionRule.KeyPath) } } "Operator" { if(-not [String]::IsNullOrWhiteSpace($ApplicationData.AppConfig.DetectionRule.Operator)){ $detection.Add("Operator", $ApplicationData.AppConfig.DetectionRule.Operator) } } "ValueName" { if(-not [String]::IsNullOrWhiteSpace($ApplicationData.AppConfig.DetectionRule.ValueName)){ $detection.Add("ValueName", $ApplicationData.AppConfig.DetectionRule.ValueName) } } "ProductVersionOperator" { if(-not [String]::IsNullOrWhiteSpace($ApplicationData.AppConfig.DetectionRule.ProductVersionOperator)){ $detection.Add("ProductVersionOperator", $ApplicationData.AppConfig.DetectionRule.ProductVersionOperator) } } "DetectionType" { if(-not [String]::IsNullOrWhiteSpace($ApplicationData.AppConfig.DetectionRule.DetectionType)){ $detection.Add("DetectionType", $ApplicationData.AppConfig.DetectionRule.DetectionType) } } "RunAs32Bit" { if([System.Convert]::ToBoolean($ApplicationData.AppConfig.DetectionRule.RunAs32Bit)){ $detection.Add("RunAs32Bit", $true) } } "ScriptFile" { if(-not [String]::IsNullOrWhiteSpace($ApplicationData.AppConfig.DetectionRule.ScriptFile)){ $detection.Add("ScriptFile", $ApplicationData.AppConfig.DetectionRule.ScriptFile) } } } } if(-not $test){ Set-AppFactoryAppDetectionRule @detection } else{ "##################### DETECTION ######################" $ApplicationData.AppConfig.DetectionRule | get-member | where-object { $_.MemberType -eq "NoteProperty" } | format-table $detection } #endregion #region FInal Steps to Import file if(-not $test){ $appFolderPath = Join-Path -Path $script:AppFactorySourceDir -ChildPath "Apps" -AdditionalChildPath $App.displayName $IconPath = Join-Path -Path $appFolderPath -ChildPath "Icon.png" Remove-Item -path $IconPath -Force $ImportFrom = ((Get-Item $AppDetailsPath).Directory).FullName Copy-Item -Path "$($ImportFrom)\Icon.png" -Destination $appFolderPath -Force -ErrorAction SilentlyContinue Copy-Item -Path "$($ImportFrom)\Detection.ps1" -Destination $appFolderPath -Force -ErrorAction SilentlyContinue $temp = Get-Content -Path "$($appFolderPath)\ApplicationConfig.json" | ConvertFrom-Json -Depth 10 $temp.GUID = $ApplicationData.AppData.GUID $temp | ConvertTo-Json -Depth 10 | Set-Content -Path "$($appFolderPath)\ApplicationConfig.json" -Force } #endregion } # [String]::IsNullOrWhiteSpace <# #> <# #> #EndRegion '.\Public\Import-PreviousVersion.ps1' 269 #Region '.\Public\Initialize-AppFactoryClientProcess.ps1' 0 function Initialize-AppFactoryClientProcess{ [CmdletBinding()] param( [Alias("Path")][Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$ClientServicePath, [Parameter()][ValidateNotNullOrEmpty()][string]$configuration = "Configuration.json", [Parameter()][string]$LocalModule = $null, [Parameter()][switch]$EnableLogging, [Parameter()][int]$retries = 5, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) # Set if we should be logging with the PSFramework Module $script:AppFactoryClientLogging = $EnableLogging.IsPresent # Where is the configuration file stored $script:AppFactoryClientSourceDir = $ClientServicePath $script:AppFactoryClientConfigDir = Join-Path -Path $script:AppFactoryClientSourceDir -ChildPath "Configurations" # Workspace $script:AppFactoryClientWorkspace = Join-Path -Path $script:AppFactoryClientSourceDir -ChildPath "Workspace" if ($script:AppFactoryClientLogging) { $AppFactoryClientLogDir = Join-Path -Path $script:AppFactoryClientSourceDir -ChildPath "Logs" # Name for the log file to be used $logFile = "$($AppFactoryClientLogDir)\AppFactoryClient-%Date%.csv" $paramSetPSFLoggingProvider = @{ Name = "logfile" InstanceName = "AppFactoryClient" FilePath = $logFile Enabled = $true Wait = $true } Set-PSFLoggingProvider @paramSetPSFLoggingProvider Write-PSFMessage -Message "Logging Configured" -Level $LogLevel -Tag "Setup" -Target "Application Factory Client" Write-PSFMessage -Message "Log File: <c='green'>$($logFile)</c>" -Level $LogLevel -Tag "Setup" -Target "Application Factory Client" Write-PSFMessage -Message "Reading Configuration File" -Level $LogLevel -Tag "Setup" -Target "Application Factory Client" } try { $configurationPath = Join-Path $script:AppFactoryClientConfigDir -ChildPath $configuration $configurationDetails = Get-Content -Path $configurationPath -ErrorAction Stop | ConvertFrom-JSON $script:AppFactoryClientClientRetries = $configurationDetails.retries $script:AppFactoryClientClientID = $configurationDetails.clientID $script:AppFactoryClientTenantID = $configurationDetails.tenantID $script:AppFactoryClientApiEndpoint = $configurationDetails.apiendpoint $script:AppFactoryClientAppRegSecret = Get-Secret -Vault $configurationDetails.keyVault -Name $configurationDetails.appregistrationSecret -AsPlainText $script:AppFactoryClientAPISecret = Get-Secret -Vault $configurationDetails.keyVault -Name $configurationDetails.apisecret $script:AppFactoryClientPrefix = $configurationDetails.prefix } catch { throw $_ } } #EndRegion '.\Public\Initialize-AppFactoryClientProcess.ps1' 49 #Region '.\Public\Initialize-AppFactoryProcess.ps1' 0 <# .DESCRIPTION This cmdlet is designed to set all the required variables and settings for the process .PARAMETER Path Where the application configuration files are stored .PARAMETER configuration The name of the configuration file if not the default .PARAMETER LocalModule If we should load the module from a local source vs installed module .PARAMETER EnableLogging If logging should be enabled with PSFramework .PARAMETER LogLevel If logging is enabled, what level of logging do we want, default is verbose. .EXAMPLE Start Application Factory with the default configuration file and no logging Initialize-AppFactoryProcess -Path "### PATH TO PROCESS FILES ###" Start Application Factory with a different configuration file and logging enabled Initialize-AppFactoryProcess -Path "### PATH TO PROCESS FILES ###" -configuration "### CONFIGURATION JSON FILE NAME ###" -EnableLogging Start Application Factory with a local module loaded for testing Initialize-AppFactoryProcess -Path "### PATH TO PROCESS FILES ###" -LocalModule "### PATH TO LOCAL MODULE ###" #> function Initialize-AppFactoryProcess{ [CmdletBinding()] [Alias("Start-AppFactory")] param( [Alias("Path")][Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$ApplicationServicePath, [Parameter()][ValidateNotNullOrEmpty()][string]$configuration = "Configuration.json", [Parameter()][string]$LocalModule = $null, [Parameter()][switch]$EnableLogging, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) # Set if we should be logging with the PSFramework Module $script:AppFactoryLogging = $EnableLogging.IsPresent if($null -ne $LocalModule){ $script:LocalModulePath = $LocalModule } # Determine what the Source Directory we aer using is $script:AppFactorySourceDir = $ApplicationServicePath # Where are the supporting files stored $script:AppFactorySupportFiles = Join-Path -Path $PSScriptRoot -ChildPath "SupportFiles" $script:AppFactorySupportTemplateFolder = Join-Path -Path $PSScriptRoot -ChildPath "Templates" $script:AppFactoryLocalSupportFiles = Join-Path -Path $script:AppFactorySourceDir -ChildPath "SupportFiles" $script:AppFactoryWorkspace = Join-Path -Path $script:AppFactorySourceDir -ChildPath "Workspace" # Setup Logging Configuration if ($script:AppFactoryLogging) { $AppFactoryLogDir = Join-Path -Path $script:AppFactorySourceDir -ChildPath "Logs" # Name for the log file to be used $logFile = "$($AppFactoryLogDir)\AppFactoryService-%Date%.csv" $paramSetPSFLoggingProvider = @{ Name = "logfile" InstanceName = "AppFactoryService" FilePath = $logFile Enabled = $true Wait = $true } Set-PSFLoggingProvider @paramSetPSFLoggingProvider Write-PSFMessage -Message "Logging Configured" -Level $LogLevel -Tag "Setup" -Target "Application Factory Service" Write-PSFMessage -Message "Log File: <c='green'>$($logFile)</c>" -Level $LogLevel -Tag "Setup" -Target "Application Factory Service" Write-PSFMessage -Message "Reading Configuration File" -Level $LogLevel -Tag "Setup" -Target "Application Factory Service" } # Where is the configuration folder $script:AppFactoryConfigDir = Join-Path -Path $script:AppFactorySourceDir -ChildPath "Configurations" $script:AppFactoryClientConfigDir = Join-Path -Path $script:AppFactorySourceDir -ChildPath "ClientConfigurations" # What is the path to the configuration file $AFConfigFile = Join-Path $script:AppFactoryconfigDir -ChildPath $configuration # Read the configuration file into an object $configDetails = Get-Content -Path $AFConfigFile -ErrorAction Stop | ConvertFrom-JSON $script:AppFactoryInstallersContainer = $configDetails.storage.installers.name $script:AppFactoryInstallersSecret = Get-Secret -Vault $configDetails.keyVault -Name $configDetails.storage.installers.secret $script:AppFactoryDeploymentsContainer = $configDetails.storage.deployments.name $script:AppFactoryDeploymentsSecret = Get-Secret -Vault $configDetails.keyVault -Name $configDetails.storage.deployments.secret $script:AppFactoryPublicFolder = $configDetails.publicContainer $script:AppFactorySharepointTenant = $configDetails.sharepoint.tenant $script:AppFactorySharepointClientID = $configDetails.sharepoint.clientId $script:AppFactorysharepointsite = $configDetails.sharepoint.sharepointsite $script:AppFactorysharepointurl = $configDetails.sharepoint.sharepointurl $script:AppFactorySharepointCertificate = $configDetails.sharepoint.certificateFile $script:AppFactorySharepointCertificateSecret = Get-Secret -Vault $configDetails.keyVault -Name $configDetails.sharepoint.certificateSecret $script:AppFactorySharepointVersionField = $configDetails.sharepoint.versionField $script:AppFactorySharepointDocumentLibrary = $configDetails.sharepoint.documentLibrary $script:AppFactoryServiceSendMailAs = $configDetails.ApplicationSendMailAs $script:AppFactoryServiceClientID = $configDetails.ApplicationClientID $script:AppFactoryServiceTenantID = $configDetails.ApplicationTenantID $script:AppFactoryServiceSecret = Get-Secret -vault $configDetails.keyVault -Name $configDetails.ApplicationSecret if ($script:AppFactoryLogging) { Write-PSFMessage -Message "Loaded variables for the Application Factory Service" -Level $LogLevel -Tag "Setup" -Target "Application Factory Service" } # Initialize the Azure Storage and Available apps # Azure Storage Contexts. The first is for exe installers, the 2nd is for payload free installers $script:appStorageContext = Connect-AppFactoryAzureStorage -storageContainer $script:AppFactoryInstallersContainer -storageSecret $script:AppFactoryInstallersSecret -LogLevel $LogLevel $script:psadtStorageContext = Connect-AppFactoryAzureStorage -storageContainer $script:AppFactoryDeploymentsContainer -storageSecret $script:AppFactoryDeploymentsSecret -LogLevel $LogLevel # Get a Hashtable of All the Current Blobs that are present so we can check to see if the version is not packaged in at least one of the containers $script:PublishedAppList = @{ "public" = Get-AzStorageBlob -Container public -Context $psadtStorageContext } $Clients = Get-AppFactoryServiceClient -LogLevel $LogLevel foreach($Client in $Clients){ $script:PublishedAppList.Add($Client.GUID, (Get-AzStorageBlob -Container $Client.GUID -Context $psadtStorageContext)) } } #EndRegion '.\Public\Initialize-AppFactoryProcess.ps1' 104 #Region '.\Public\New-AppFactoryApp.ps1' 0 function New-AppFactoryApp { [CmdletBinding(DefaultParameterSetName = 'PSADTECNO')] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][String]$displayName, [Parameter()][ValidateNotNullOrEmpty()][String]$AppFolderName, [Parameter()][String]$description, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][String]$publisher, [Parameter()][String]$notes = "", [Parameter()][String]$owner = "", [Parameter()][String]$informationURL = "", [Parameter()][String]$privacyURL = "", [Parameter(Mandatory = $true)][ValidateSet("StorageAccount", "Sharepoint", "Winget", "Evergreen", "PSADT", "ECNO", "LocalStorage")][String]$AppSource, [Parameter(Mandatory = $true, ParameterSetName = 'WingetEvergreen')] [ValidateNotNullOrEmpty()][string]$appID, [Parameter(Mandatory = $true, ParameterSetName = 'AzureLocalStorage')] [Parameter(Mandatory = $true, ParameterSetName = 'Sharepoint')] [Parameter(Mandatory = $true, ParameterSetName = 'WingetEvergreen')] [Alias("appSetupName")][ValidateNotNullOrEmpty()][string]$AppSetupFileName = "", [Parameter(Mandatory = $true, ParameterSetName = 'ECNO')] [Parameter(Mandatory = $true, ParameterSetName = 'AzureLocalStorage')] [Alias("storageContainerName")][ValidateNotNullOrEmpty()][string]$StorageAccountContainerName = "", [Parameter()][String[]]$ExtraFiles = @(), [Parameter()][PSCustomObject]$filterOptions = @{}, [Parameter()][String[]]$publishTo = @(), [Parameter()][String]$AppVersion = "<replaced_by_build>", [Parameter()][String[]]$AvailableVersions = @(), [Parameter()][ValidateSet("system", "user")][string]$InstallExperience = "system", [Parameter()][ValidateSet("suppress", "force", "basedOnReturnCode", "allow")][string]$DeviceRestartBehavior = "suppress", [Parameter()][ValidateSet("true", "false")][string]$AllowAvailableUninstall = $true, [Parameter()][ValidateSet("W10_1607", "W10_1703", "W10_1709", "W10_1809", "W10_1909", "W10_2004", "W10_20H2", "W10_21H1", "W10_21H2", "W10_22H2", "W11_21H2", "W11_22H2")][string]$MinimumSupportedWindowsRelease = "W10_1607", [Parameter()][ValidateSet("All", "x64", "x86")][string]$Architecture = "All", [Parameter()][String[]]$DependsOn = @(), [Parameter()][bool]$active = $true, [Parameter()][bool]$pauseUpdate = $false, [Parameter()][switch]$force, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) if (-not $PSBoundParameters.ContainsKey("AppFolderName")) { $AppFolderName = $displayName } try { # Create the package folders for the application we are creating New-AppFactoryAppFolder -displayName $displayName -folderName $AppFolderName -LogLevel $LogLevel -Force $force | Out-Null } catch { throw $_ } # Read Template Config File $configFilePath = Join-Path -Path $script:AppFactorySupportTemplateFolder -ChildPath "Application" -AdditionalChildPath "ApplicationConfig.json" $configFIle = Get-Content -Path $configFilePath | ConvertFrom-Json # Get a new GUID for the application $appGUID = (New-GUID).Guid # Set Configuration File values $configFIle.GUID = $appGUID $configfile.Information.DisplayName = $displayName $configfile.Information.AppFolderName = $AppFolderName $configfile.Information.AppVersion = $AppVersion $configfile.Information.Description = $Description $configfile.Information.Publisher = $Publisher $configfile.Information.Notes = $Notes $configfile.Information.owner = $owner $configfile.Information.informationURL = $informationURL $configfile.Information.PrivacyURL = $PrivacyURL $configfile.SourceFiles.AppSource = $AppSource $configfile.SourceFiles.AppID = $AppID $configfile.SourceFiles.AppSetupFileName = $AppSetupFileName $configfile.SourceFiles.StorageAccountContainerName = $StorageAccountContainerName $configfile.SourceFiles.ExtraFiles = $ExtraFiles $configfile.SourceFiles.FilterOptions = $FilterOptions $configfile.SourceFiles.publishTo = $publishTo $configfile.SourceFiles.active = $active $configfile.SourceFiles.pauseUpdate = $pauseUpdate $configfile.Program.InstallExperience = $InstallExperience $configfile.Program.DeviceRestartBehavior = $DeviceRestartBehavior $configfile.Program.AllowAvailableUninstall = $AllowAvailableUninstall $configfile.RequirementRule.MinimumSupportedWindowsRelease = $MinimumSupportedWindowsRelease $configfile.RequirementRule.Architecture = $Architecture # If depends on was passed, check to make sure that the application exists if ($PSBoundParameters.ContainsKey("DependsOn")) { foreach ($app in $DependsOn) { $exists = Get-AppFactoryApp -appGUID $app if ($null -eq $exists) { Write-PSFMessage -Message "Error Encountered: Dependent Application with GUID $($app) does not exist" -Level "Error" -Tag "Application", "$($displayName)", "$($appGUID)" -Target "Application Factory Service" throw "Dependent Application with GUID $($app) does not exist" } } $configfile.SourceFiles.DependsOn = $DependsOn } # Create the configuration for the application try { Write-AppConfiguration -configfile $configfile -LogLevel $LogLevel } catch { Write-PSFMessage -Message "Error Encountered: $($_)" -Level "Error" -Tag "Application", "$($displayName)", "$($configFIle.GUID)" -Target "Application Factory Service" throw $_ } return $configfile } #EndRegion '.\Public\New-AppFactoryApp.ps1' 102 #Region '.\Public\New-AppFactoryClientSetup.ps1' 0 function New-AppFactoryClientSetup { [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$path, [Parameter()][switch]$createSecretVault, [Parameter()][string]$vaultName = "ApplicationFactory", [Parameter(Mandatory = $true)][string]$AppRegistrationClientID, [Parameter(Mandatory = $true)][string]$AppRegistrationTenantID, [Parameter(Mandatory = $true)][string]$AppRegSecretName, [Parameter()][string]$AppRegSecretValue, [Parameter(Mandatory = $true)][string]$APIEndpoint, [Parameter(Mandatory = $true)][string]$APISecretName, [Parameter()][string]$prefix, [Parameter()][string]$APISecretValue ) If (-Not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { throw "You need to run this function as administrator." } # List of Required Moodules $modules = @("Microsoft.PowerShell.SecretManagement", "SecretManagement.JustinGrote.CredMan", "PSFramework", "UGDSB.PS.Graph","IntuneWin32App") # Install Required Modules foreach ($module in $modules) { Install-Module -Name $module -Scope AllUsers } # Create Secret Vault if configured to do so if ($PSBoundParameters.ContainsKey("createSecretVault")) { Register-SecretVault -Name $vaultName -ModuleName "SecretManagement.JustinGrote.CredMan" } # Create the secrets if values where passed if ($PSBoundParameters.ContainsKey("AppRegSecretValue")) { Set-Secret -Name $AppRegSecretName -Secret $AppRegSecretValue -Vault $vaultName } if ($PSBoundParameters.ContainsKey("APISecretValue")) { Set-Secret -Name $APISecretName -Secret $APISecretValue -Vault $vaultName } # Create the base folder if (-not (Test-Path -path $path)) { New-Item -Path $path -ItemType Directory -Force } # Create the Client Folders $folders = @("Apps", "Configurations", "Logs", "Workspace") foreach ($folder in $folders) { $folderPath = Join-Path -Path $path -ChildPath $folder if (-not (Test-Path -path $folderPath)) { New-Item -Path $folderPath -ItemType Directory -Force } } # Create the Client Configurations $config = @{ keyVault = $vaultName clientID = $AppRegistrationClientID tenantID = $AppRegistrationTenantID appregistrationSecret = $AppRegSecretName apiendpoint = $APIEndpoint apisecret = $APISecretName prefix = $prefix } $configPath = Join-Path -Path $path -ChildPath "Configurations" -AdditionalChildPath "Configuration.json" $config | ConvertTo-Json | Set-Content -Path $configPath } #EndRegion '.\Public\New-AppFactoryClientSetup.ps1' 59 #Region '.\Public\New-AppFactoryIntuneFile.ps1' 0 function New-AppFactoryIntuneFile { [CmdletBinding()] [OutputType([System.Collections.Generic.List[PSCustomObject]])] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][PSCustomObject]$applicationList, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) # Create blank list to store the applications that we will be moving forward with. $applications = [System.Collections.Generic.List[PSCustomObject]]@() # Loop through each of the applications foreach ($application in $applicationList) { try{ $SourceFolder = Join-Path -Path $script:AppFactoryWorkspace -ChildPath "Publish" -AdditionalChildPath $application.Information.AppFolderName $IntuneWinAppUtilPath = Join-Path -Path $script:AppFactorySupportFiles -ChildPath "IntuneWinAppUtil.exe" $OutputPackage = Join-Path -Path $SourceFolder -ChildPath "$([System.IO.Path]::GetFileNameWithoutExtension($application.PackageInformation.SetupFile)).intunewin" $param = @{ FilePath = $IntuneWinAppUtilPath ArgumentList = "-c ""$($SourceFolder)"" -s ""$($application.PackageInformation.SetupFile)"" -o ""$($SourceFolder)"" -q" LoadUserProfile = $false Passthru = $true UseNewEnvironment = $true Wait = $true } $process = Start-Process @param if($process.ExitCode -eq 0){ Rename-Item -path $OutputPackage -NewName "$($application.Information.DisplayName).intunewin" -Force } else{ throw "Process failed with exit code $($process.ExitCode)" } $application.SourceFiles | Add-Member -MemberType NoteProperty -Name IntunePackage -Value "$($application.Information.DisplayName).intunewin" -Force $applications.Add($application) } catch{ Write-PSFMessage -Message "[<c='green'>$($application.Information.DisplayName)</c>] Unable to create intune win files. Error: $($_)" -Level "Warning" -Tag "Process",$application.Information.DisplayName -Target "Application Factory Service" continue } } return $applications } #EndRegion '.\Public\New-AppFactoryIntuneFile.ps1' 41 #Region '.\Public\New-AppFactoryPackage.ps1' 0 function New-AppFactoryPackage{ [CmdletBinding()] [OutputType([System.Collections.Generic.List[PSCustomObject]])] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][System.Collections.Generic.List[PSCustomObject]]$applicationList, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) # Create a list to store the results of the process $applications = [System.Collections.Generic.List[PSCustomObject]]@() foreach ($application in $applicationList) { try{ $AppPublishFolderPath = Join-Path -Path $script:AppFactoryWorkspace -ChildPath "Publish" -AdditionalChildPath $application.Information.AppFolderName $AppSetupFolderPath = Join-Path -Path $script:AppFactoryWorkspace -ChildPath "Installers" -AdditionalChildPath $application.Information.AppFolderName $ApplicationDirectory = Join-Path -Path $script:AppFactorySourceDir -ChildPath "Apps" -AdditionalChildPath $application.Information.AppFolderName $ToolkitFile = Join-Path -Path $script:AppFactoryWorkspace -ChildPath "Publish" -AdditionalChildPath $application.Information.AppFolderName,"Invoke-AppDeployToolkit.ps1" Remove-Item -Path $AppPublishFolderPath -Force -Recurse -ErrorAction SilentlyContinue #region Create Publish Folder try { New-Item -Path $AppPublishFolderPath -ItemType Directory -ErrorAction "Stop" | Out-Null } catch { throw "[$($application.Information.DisplayName)] Failed to create '$($AppPublishFolderPath)' with error message: $($_.Exception.Message)" } #endregion #region Copy PSADT template files try{ Copy-Item -Path "$($script:AppFactorySupportTemplateFolder)\PSADT\*" -Destination $AppPublishFolderPath -Recurse -Force -Confirm:$false } catch { throw "[$($application.Information.DisplayName)] Unable to copy template files: $($_.Exception.Message)" } #endregion #region Copy Application Files if($application.SourceFiles.AppSource -ne "PSADT"){ try{ New-Item -Path "$($AppPublishFolderPath)\Files" -ItemType Directory -Force | Out-Null Copy-Item -Path "$($AppSetupFolderPath)\*" -Destination "$($AppPublishFolderPath)\Files" -Recurse -Force -Confirm:$false } catch { throw "[$($application.Information.DisplayName)] Unable to copy template files: $($_.Exception.Message)" } } #endregion #region Inject Install/Uninstall in Deployment Script $ToolkitContent = Get-Content -Path $ToolkitFile -Raw $ToolkitContent = $ToolkitContent -replace "###INTUNEAPPNAME###", $application.Information.DisplayName $ToolkitContent = $ToolkitContent -replace "###APPPUBLISHER###", $application.Information.Publisher $ToolkitContent = $ToolkitContent -replace "###VERSION###", $application.SourceFiles.PackageVersion $ToolkitContent = $ToolkitContent -replace "###APPARCH###", $application.RequirementRule.Architecture $ToolkitContent = $ToolkitContent -replace "###AppLang###", "English" $ToolkitContent = $ToolkitContent -replace "###APPDATE###", (Get-Date).ToShortDateString() $InstallerContent = Get-Content -Path "$($ApplicationDirectory)\install.ps1" -ErrorAction SilentlyContinue $UninstallerContent = Get-Content -Path "$($ApplicationDirectory)\uninstall.ps1" -ErrorAction SilentlyContinue $ToolKitInstallStart = $ToolkitContent -split " ## <Perform Installation tasks here>" $ToolkitUninstallStart = $ToolKitInstallStart[1] -split " ## <Perform Uninstallation tasks here>" $NewContent = [System.Collections.Generic.List[string]]::new() foreach($line in $ToolKitInstallStart[0]){ $NewContent.Add($line) } $NewContent.Add(" ## <Perform Installation tasks here>") foreach($line in $InstallerContent){ $NewContent.Add(($line -replace "###SETUPFILENAME###", $($application.SourceFiles.AppSetupFileName))) } foreach($line in $ToolkitUninstallStart[0]){ $NewContent.Add($line) } $NewContent.Add(" ## <Perform Uninstallation tasks here>") foreach($line in $UninstallerContent){ $NewContent.Add(($line -replace "###SETUPFILENAME###", $($application.SourceFiles.AppSetupFileName))) } foreach($line in $ToolkitUninstallStart[1]){ $NewContent.Add($line) } Out-File -InputObject $NewContent -FilePath $ToolkitFile -Encoding "utf8" -Force -Confirm:$false #endregion #region Update Install Experience if set to user if($application.Program.InstallExperience -eq "User"){ $configPSPath = Join-Path -Path $AppPublishFolderPath -ChildPath "Config" -AdditionalChildPath "config.psd1" $configPSContent = Get-Content -Path $configPSPath $configPSContent = $configPSContent.replace('RequireAdmin = $true','RequireAdmin = $false') $configPSContent | Out-File $configPSPath -Force } #endregion $iconPath = Join-Path -Path $AppFactorySourceDir -ChildPath "Apps" -AdditionalChildPath $application.Information.AppFolderName,"Icon.png" $iconDestination = Join-Path -Path $AppPublishFolderPath -ChildPath "Icon.png" Copy-Item -Path $iconPath -Destination $iconDestination -Force -Confirm:$false if($application.DetectionRule.Type -eq "Script"){ $detectionPath = Join-Path -Path $AppFactorySourceDir -ChildPath "Apps" -AdditionalChildPath $application.Information.AppFolderName,$application.DetectionRule.ScriptFile $detectionDestination = Join-Path -Path $AppPublishFolderPath -ChildPath $application.DetectionRule.ScriptFile $detectionContent = Get-Content -Path $detectionPath -Raw $detectionContent = $detectionContent -replace "###VERSION###", $application.SourceFiles.PackageVersion Out-File -InputObject $detectionContent -FilePath $detectionDestination -Encoding "utf8" -Force -Confirm:$false } } catch{ if ($script:AppFactoryLogging) { Write-PSFMessage -Message $_ -Level "Error" -Tag "Application", "$($application.Information.DisplayName)", "Error" -Target "Application Factory Service" } continue } $applications.add($application) } return $applications } #EndRegion '.\Public\New-AppFactoryPackage.ps1' 106 #Region '.\Public\New-AppFactoryServiceClient.ps1' 0 <# .DESCRIPTION This cmdlet is designed to create a new organization .PARAMETER clientName The name of the organization .PARAMETER clientContacts The list of contacts for the organization .PARAMETER force Overwrite the current file with a new configuration. .PARAMETER LogLevel If logging is enabled, what level of logging do we want, default is verbose. .EXAMPLE Create a new organization New-AppFactoryClient -clientName "### Organization Name ###" Create a new organization with contacts New-AppFactoryClient -clientName "### Organization Name ###" -clientContacts "### Contact 1 ###", "### Contact 2 ###" #> function New-AppFactoryServiceClient { [CmdletBinding()] [Alias("New-AppFactoryOrganization")] [OutputType([System.Collections.Generic.List[PSCustomObject]])] param( [Alias('Name')][Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$clientName, [Alias('contactList')][Parameter()][string[]]$clientContacts = @(), [Parameter()][switch]$force, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) # Generate a unique GUID for client $GUID = (New-GUID).Guid # Create the client file to write out $obj = [PSCustomObject]@{ GUID = $GUID Name = $clientName Contacts = $clientContacts } # Path for the new client file $clientFile = Join-Path -Path $script:AppFactorySourceDir -ChildPath "Clients" -AdditionalChildPath "$($clientName).json" # Client File Path if ($script:AppFactoryLogging) { Write-PSFMessage -Message "Creating client with GUID: <c='green'>$($GUID)</c>" -Level $LogLevel -Tag "Clients", "$($clientName)" -Target "Application Factory Service" Write-PSFMessage -Message "Client file path: <c='green'>$($clientFile)</c>" -Level $LogLevel -Tag "Clients", "$($clientName)" -Target "Application Factory Service" } # First write out the client json try { if ((Test-Path -Path $clientFile) -and -not $force.IsPresent) { throw "Client already exists with this name." } $obj | ConvertTo-Json | Out-File -FilePath $clientFile -Force Write-PSFMessage -Message "Created client configuration file." -Level $LogLevel -Tag "Clients", "$($clientName)" -Target "Application Factory Service" } catch { Write-PSFMessage -Message "Error Encountered: $($_)" -Level "Error" -Tag "Clients", "$($clientName)" -Target "Application Factory Service" throw $_ } # Create Azure Storage Container to store client specific applications try { $clientStorageContainerContext = Connect-AppFactoryAzureStorage -storageContainer $script:AppFactoryDeploymentsContainer -storageSecret $script:AppFactoryDeploymentsSecret New-AzStorageContainer -Name $GUID -Permission Off -Context $clientStorageContainerContext | Out-Null if ($script:AppFactoryLogging) { Write-PSFMessage -Message "Created clients storage container <c='green'>$($GUID)</c>" -Level $LogLevel -Tag "Clients", "$($clientName)" -Target "AppFactory" } } catch { Remove-Item -Path $clientFile -Force Write-PSFMessage -Message "Error Encountered: $($_)" -Level "Error" -Tag "Clients", "$($clientName)" -Target "Application Factory Service" throw $_ } return $obj } #EndRegion '.\Public\New-AppFactoryServiceClient.ps1' 73 #Region '.\Public\New-PSUGUIAppTabs.ps1' 0 function New-PSUGUIAppTabs{ [cmdletbinding()] param() New-UDTabs -Tabs { New-UDTab -Text 'Information' -Content { New-UDElement -Tag "div" -ClassName "card-body rounded" -Content { New-UDElement -Tag "table" -Attributes @{ "style" = @{ "width" = "100%"; } "cellpadding" = "1" } -Content { New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "GUID:" -id "ApplicationGUID" -placeholder "" -disabled -item_colspan 3 -item_width 80 } New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Name:" -id "ApplicationName" -placeholder "Application Name" New-PSUGUIInputTextGroup -Label "Publisher:" -id "Publisher" -placeholder "Publisher Name" } New-UDElement -Tag "tr" -Content { New-PSUGUIInputSelectGroup -Label "Versions:" -id "AvailableVersions" -placeholder "Available Versions" -onchangeAction "AvailableVersionsSelection" New-PSUGUIInputTextGroup -Label "Owner:" -id "Owner" -placeholder "Owner Name" } New-UDElement -Tag "tr" -Content { New-PSUGUISwitch -Label "Active:" -id "Active" -Checked New-PSUGUISwitch -Label "Paused:" -id "pauseUpdate" } New-UDElement -Tag "tr" -Content { New-PSUGUIInputSelectGroup -Label "Install As:" -id "InstallExperience" -options @("system", "user") -DefaultValue "System" New-PSUGUUploadIcon -Label "Icon:" -id "IconFile" -placeholder "Upload Icon" -Output "$($env:TEMP)\PSUApp_Icon.png" } New-UDElement -Tag "tr" -Content { New-PSUGUIInputSelectGroup -Label "Clients:" -id "Client" -placeholder "Client Specific" -multiselect -options ((Get-AppFactoryServiceClient | Select-Object Name).Name | Sort-Object) -item_colspan 3 -item_width 80 } New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Information URL:" -id "InformationURL" -placeholder "Information URL" -item_colspan 3 -item_width 80 } New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Privacy URL:" -id "PrivacyURL" -placeholder "Privacy URL" -item_colspan 3 -item_width 80 } New-UDElement -Tag "tr" -Content { New-PSUGUIInputSelectGroup -Label "Architecture:" -id "Architecture" -placeholder "Available Architecture" -options @("All", "x86", "x64") -DefaultValue "All" New-PSUGUIInputSelectGroup -Label "Min Win OS:" -id "MinimumSupportedWindowsRelease" -placeholder "Minimum Windows OS Version" -options @("W10_1607", "W10_1703", "W10_1709", "W10_1809", "W10_1909", "W10_2004", "W10_20H2", "W10_21H1", "W10_21H2", "W10_22H2", "W11_21H2", "W11_22H2") -DefaultValue "W10_1607" } New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextboxGroup -Label "Description:" -id "Description" -placeholder "Description" -item_colspan 3 -item_width 80 } New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextboxGroup -Label "Notes:" -id "Notes" -placeholder "Notes" -item_colspan 3 -item_width 80 } } } } New-UDTab -Text 'Source' -Content { New-UDElement -Tag "div" -ClassName "card-body rounded" -Content { New-UDElement -Tag "table" -Attributes @{ "style" = @{ "width" = "100%"; } "cellpadding" = "1" } -Content { New-UDElement -Tag "tr" -Content { New-PSUGUIInputSelectGroup -Label "Source:" -id "Source" -placeholder "Select Source" -options @("StorageAccount", "Sharepoint", "Winget", "Evergreen", "PSADT", "ECNO", "LocalStorage") -item_colspan 3 -item_width 80 -onchangeAction "SourceSelection" } } } New-UDelement -Tag "div" -ClassName "card-body rounded" -id "SourceSelectionFields" -Content {} } New-UDTab -Text 'Install' -Content { New-UDElement -Tag "div" -ClassName "card-body rounded" -Content { New-UDElement -Tag "table" -Attributes @{ "style" = @{ "width" = "100%"; } "cellpadding" = "1" } -Content { New-UDElement -Tag "tr" -Content { New-PSUGUIInputSelectGroup -Label "Install:" -id "Install" -placeholder "Select Install Type" -options @("None", "EXE", "MSI", "ECNO", "Script") -item_colspan 3 -item_width 80 -onchangeAction "InstallSelection" } } } New-UDelement -Tag "div" -ClassName "card-body rounded" -id "InstallSelectionFields" -Content {} } New-UDTab -Text 'Uninstall' -Content { New-UDElement -Tag "div" -ClassName "card-body rounded" -Content { New-UDElement -Tag "table" -Attributes @{ "style" = @{ "width" = "100%"; } "cellpadding" = "1" } -Content { New-UDElement -Tag "tr" -Content { New-PSUGUIInputSelectGroup -Label "Uninstall:" -id "Uninstall" -placeholder "Select Uninstall Type" -options @("NONE", "MSI", "EXE", "NAME", "GUID", "ECNO", "Script") -item_colspan 3 -item_width 80 -onchangeAction "UninstallSelection" } } } New-UDelement -Tag "div" -ClassName "card-body rounded" -id "UninstallSelectionFields" -Content {} } New-UDTab -Text 'Detection' -Content { New-UDElement -Tag "div" -ClassName "card-body rounded" -Content { New-UDElement -Tag "table" -Attributes @{ "style" = @{ "width" = "100%"; } "cellpadding" = "1" } -Content { New-UDElement -Tag "tr" -Content { New-PSUGUIInputSelectGroup -Label "Detection:" -id "Detection" -placeholder "Select Detection Type" -options @("MSI", "Registry Version", "Registry Existance", "Script") -item_colspan 3 -item_width 80 -onchangeAction "DetectionSelection" } } } New-UDelement -Tag "div" -ClassName "card-body rounded" -id "DetectionSelectionFields" -Content {} } } } #EndRegion '.\Public\New-PSUGUIAppTabs.ps1' 121 #Region '.\Public\New-PSUGUIDetectionMSI.ps1' 0 function New-PSUGUIDetectionMSI{ [cmdletbinding()] param( [Parameter()][PSCustomObject]$SourceData ) New-UDElement -Tag "table" -Attributes @{ "style" = @{ "width" = "100%"; } "cellpadding" = "1" } -Content { New-UDElement -Tag "tr" -Content { New-PSUGUIInputSelectGroup -Label "Version Comparison:" -id "Detection_VersionCompare" -placeholder "" -options @("notConfigured","equal","notEqual","greaterThanOrEqual","greaterThan","lessThanOrEqual","lessThan") -item_colspan 3 -item_width 80 -defaultValue $SourceData.ProductVersionOperator } } } #EndRegion '.\Public\New-PSUGUIDetectionMSI.ps1' 18 #Region '.\Public\New-PSUGUIDetectionRegistryExistance.ps1' 0 function New-PSUGUIDetectionRegistryExistance{ [cmdletbinding()] param( [Parameter()][PSCustomObject]$SourceData ) New-UDElement -Tag "table" -Attributes @{ "style" = @{ "width" = "100%"; } "cellpadding" = "1" } -Content { $registryKey = $SourceData.keyPath -split "\\" if($registryKey[-1] -ne "###PRODUCTCODE###"){$value = $registryKey[-1]} else{$value = ""} New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Registry Key:" -id "Detection_Keypath" -placeholder "### Only set if do not want to detect automatically from MSI ###" -item_width 80 -item_colspan 3 -Value $value } New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Registry Item:" -id "Detection_Item" -placeholder "DisplayVersion" -item_width 80 -item_colspan 3 -Value $SourceData.valueName } New-UDElement -Tag "tr" -Content { New-PSUGUIInputSelectGroup -Label "Detection Type:" -id "Detection_Operator" -placeholder "" -options @("notConfigured","equal","notEqual","greaterThanOrEqual","greaterThan","lessThanOrEqual","lessThan") -item_colspan 3 -item_width 80 -DefaultValue $SourceData.operator } New-UDElement -Tag "tr" -Content { New-PSUGUISwitch -Label "32-Bit:" -id "Detection_32bit" -Checked:$([System.Convert]::ToBoolean($SourceData.Check32BitOn64System)) } } } #EndRegion '.\Public\New-PSUGUIDetectionRegistryExistance.ps1' 30 #Region '.\Public\New-PSUGUIDetectionRegistryVersion.ps1' 0 function New-PSUGUIDetectionRegistryVersion{ [cmdletbinding()] param( [Parameter()][PSCustomObject]$SourceData ) New-UDElement -Tag "table" -Attributes @{ "style" = @{ "width" = "100%"; } "cellpadding" = "1" } -Content { $registryKey = $SourceData.keyPath -split "\\" if($registryKey[-1] -ne "###PRODUCTCODE###"){$value = $registryKey[-1]} else{$value = ""} New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Registry Key:" -id "Detection_Keypath" -placeholder "### Only set if do not want to detect automatically from MSI ###" -item_width 80 -item_colspan 3 -Value $value } New-UDElement -Tag "tr" -Content { New-PSUGUISwitch -Label "32-Bit:" -id "Detection_32bit" -Checked:$([System.Convert]::ToBoolean($SourceData.Check32BitOn64System)) } } } #EndRegion '.\Public\New-PSUGUIDetectionRegistryVersion.ps1' 24 #Region '.\Public\New-PSUGUIDetectionScript.ps1' 0 function New-PSUGUIDetectionScript{ [cmdletbinding()] param( [Parameter()][PSCustomObject]$SourceData, [Parameter()][string]$scriptPath ) New-UDElement -Tag "table" -Attributes @{ "style" = @{ "width" = "100%"; } "cellpadding" = "1" } -Content { New-UDElement -Tag "tr" -Content { if(Test-Path $scriptPath){ $code = Get-Content -Path $scriptPath -ErrorAction SilentlyContinue } New-PSUGUIInputCode -id "Detection_Script" -item_colspan 4 -Code ($code -join "`n") } New-UDElement -Tag "tr" -Content { New-PSUGUISwitch -Label "32-Bit:" -id "Detection_Script_32bit" -Checked:$([System.Convert]::ToBoolean($SourceData.RunAs32Bit)) } } } #EndRegion '.\Public\New-PSUGUIDetectionScript.ps1' 25 #Region '.\Public\New-PSUGUIInstallEXE.ps1' 0 function New-PSUGUIInstallEXE{ [cmdletbinding()] param( [Parameter()][PSCustomObject]$SourceData ) New-UDElement -Tag "table" -Attributes @{ "style" = @{ "width" = "100%"; } "cellpadding" = "1" } -Content { New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Setup Name:" -id "Install_installer" -placeholder "### Only set if not the same download file ###" -item_width 80 -item_colspan 3 -Value $SourceData.installer } New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Parameters:" -id "Install_argumentList" -placeholder "Parameters" -item_width 80 -item_colspan 3 -Value $SourceData.argumentList } New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Conflicting Processes (Start):" -id "Install_conflictingProcessStart" -placeholder "Comma seperated list of conflicting processes" -item_width 80 -item_colspan 3 -Value ($SourceData.conflictingProcessStart -Join ", ") } New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Conflicting Processes (End):" -id "Install_conflictingProcessEnd" -placeholder "Comma seperated list of conflicting processes" -item_width 80 -item_colspan 3 -Value ($SourceData.conflictingProcessEnd -Join ", ") } New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Ignore Exit Codes:" -id "Install_ignoreExitCodes" -placeholder "Comma seperated list of exit codes to ignore" -item_width 80 -item_colspan 3 -Value ($SourceData.ignoreExitCodes -Join ", ") } New-UDElement -Tag "tr" -Content { New-PSUGUISwitch -Label "WIM:" -id "Install_WIM" -Checked:$SourceData.wim New-PSUGUISwitch -Label "Secure Argument List:" -id "Install_secureArgumentList" -Checked:$SourceData.secureArgumentList } } } #EndRegion '.\Public\New-PSUGUIInstallEXE.ps1' 35 #Region '.\Public\New-PSUGUIInstallMSI.ps1' 0 function New-PSUGUIInstallMSI{ [cmdletbinding()] param( [Parameter()][PSCustomObject]$SourceData ) New-UDElement -Tag "table" -Attributes @{ "style" = @{ "width" = "100%"; } "cellpadding" = "1" } -Content { New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Setup Name:" -id "Install_installer" -placeholder "### Only set if not the same download file ###" -item_width 80 -item_colspan 3 -Value $SourceData.installer } New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Transform (MST):" -id "Install_transforms" -placeholder "MST File" -item_width 80 -item_colspan 3 -Value $SourceData.transforms } New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Parameters:" -id "Install_additionalArgumentList" -placeholder "Parameters" -item_width 80 -item_colspan 3 -Value $SourceData.additionalArgumentList } New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Conflicting Processes (Start):" -id "Install_conflictingProcessStart" -placeholder "Comma seperated list of conflicting processes" -item_width 80 -item_colspan 3 -Value ($SourceData.conflictingProcessStart -Join ", ") } New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Conflicting Processes (End):" -id "Install_conflictingProcessEnd" -placeholder "Comma seperated list of conflicting processes" -item_width 80 -item_colspan 3 -Value ($SourceData.conflictingProcessEnd -Join ", ") } New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Ignore Exit Codes:" -id "Install_ignoreExitCodes" -placeholder "Comma seperated list of exit codes to ignore" -item_width 80 -item_colspan 3 -Value ($SourceData.ignoreExitCodes -Join ", ") } New-UDElement -Tag "tr" -Content { New-PSUGUISwitch -Label "WIM:" -id "Install_WIM" -Checked:$SourceData.wim New-PSUGUISwitch -Label "Secure Argument List:" -id "Install_secureArgumentList" -Checked:$SourceData.secureArgumentList } New-UDElement -Tag "tr" -Content { New-PSUGUISwitch -Label "Skip Already Installed Check:" -id "Install_SkipMSIAlreadyInstalledCheck" -Checked:$SourceData.SkipMSIAlreadyInstalledCheck } } } #EndRegion '.\Public\New-PSUGUIInstallMSI.ps1' 40 #Region '.\Public\New-PSUGUIInstallScript.ps1' 0 function New-PSUGUIInstallScript{ [cmdletbinding()] param( [Parameter()][PSCustomObject]$SourceData ) New-UDElement -Tag "table" -Attributes @{ "style" = @{ "width" = "100%"; } "cellpadding" = "1" } -Content { New-UDElement -Tag "tr" -Content { New-PSUGUIInputCode -id "Install_Script" -item_colspan 4 -Code $SourceData.Script } } } #EndRegion '.\Public\New-PSUGUIInstallScript.ps1' 18 #Region '.\Public\New-PSUGUISourceECNO.ps1' 0 function New-PSUGUISourceECNO{ [cmdletbinding()] param( [Parameter()][PSCustomObject]$SourceData ) New-UDElement -Tag "table" -Attributes @{ "style" = @{ "width" = "100%"; } "cellpadding" = "1" } -Content { New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Folder/Container:" -id "StorageContainer" -placeholder "Folder/Container Name" -Value $SourceData.storageAccountContainerName } } } #EndRegion '.\Public\New-PSUGUISourceECNO.ps1' 18 #Region '.\Public\New-PSUGUISourceEvergreen.ps1' 0 function New-PSUGUISourceEvergreen{ [cmdletbinding()] param( [Parameter()][PSCustomObject]$SourceData ) New-UDElement -Tag "table" -Attributes @{ "style" = @{ "width" = "100%"; } "cellpadding" = "1" } -Content { New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Installer:" -id "Installer" -placeholder "Installer File Name" -Value $SourceData.appSetupFileName New-PSUGUIInputTextGroup -Label "Evergreen ID:" -id "AppID" -placeholder "Evergreen ID" -Value $SourceData.appID } New-UDElement -Tag "tr" -content {New-UDElement -Tag 'td' -content {New-UDElement -Tag "br" -content {}}} New-UDElement -Tag "tr" -Content { New-UDElement -Tag "td" -Content { New-UDTypography -Text "Filter Options" -Variant "h6" -ClassName "card-title rounded x-card-title" } -Attributes @{Colspan = 4 } } New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Architecture:" -id "Filter_Architecture" -placeholder "" -Value $SourceData.filterOptions.architecture New-PSUGUIInputTextGroup -Label "Platform:" -id "Filter_Platform" -placeholder "" -Value $SourceData.filterOptions.Platform } New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Channel:" -id "Filter_Channel" -placeholder "" -Value $SourceData.filterOptions.Channel New-PSUGUIInputTextGroup -Label "Type:" -id "Filter_Type" -placeholder "" -Value $SourceData.filterOptions.Type } New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Installer Type:" -id "Filter_InstallerType" -placeholder "" -Value $SourceData.filterOptions.InstallerType New-PSUGUIInputTextGroup -Label "Release:" -id "Filter_Release" -placeholder "" -Value $SourceData.filterOptions.Release } New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Language:" -id "Filter_Language" -placeholder "" -Value $SourceData.filterOptions.Language New-PSUGUIInputTextGroup -Label "Image Type:" -id "Filter_ImageType" -placeholder "" -Value $SourceData.filterOptions.ImageType } } } #EndRegion '.\Public\New-PSUGUISourceEvergreen.ps1' 41 #Region '.\Public\New-PSUGUISourcePSADT.ps1' 0 function New-PSUGUISourcePSADT{ [cmdletbinding()] param( [Parameter()][PSCustomObject]$SourceData ) New-UDElement -Tag "table" -Attributes @{ "style" = @{ "width" = "100%"; } "cellpadding" = "1" } -Content { New-UDElement -Tag "tr" -Content { if(-not $SourceData -or $SourceData.AppVersion -eq "<replaced_by_build>"){ [version]$VersionData = [Version]"1.0.0" } else{ [version]$VersionData = [Version]$SourceData.AppVersion } New-PSUGUIInputTextGroup -Label "Script Version:" -id "AppVersion" -placeholder "Script Version i.e. 1.0.0" -Value $VersionData } } } #EndRegion '.\Public\New-PSUGUISourcePSADT.ps1' 24 #Region '.\Public\New-PSUGUISourceStorageAccount.ps1' 0 function New-PSUGUISourceStorageAccount { [cmdletbinding()] [Alias("New-PSUGUISourceSharepoint")] param( [Parameter()][PSCustomObject]$SourceData ) New-UDElement -Tag "table" -Attributes @{ "style" = @{ "width" = "100%"; } "cellpadding" = "1" } -Content { New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Installer:" -id "Installer" -placeholder "Installer File Name" -Value $SourceData.appSetupFileName New-PSUGUIInputTextGroup -Label "Folder/Container:" -id "StorageContainer" -placeholder "Folder/Container Name" -Value $SourceData.storageAccountContainerName } } } #EndRegion '.\Public\New-PSUGUISourceStorageAccount.ps1' 20 #Region '.\Public\New-PSUGUISourceWinget.ps1' 0 function New-PSUGUISourceWinget{ [cmdletbinding()] param( [Parameter()][PSCustomObject]$SourceData ) New-UDElement -Tag "table" -Attributes @{ "style" = @{ "width" = "100%"; } "cellpadding" = "1" } -Content { New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Installer:" -id "Installer" -placeholder "Installer File Name" -Value $SourceData.appSetupFileName New-PSUGUIInputTextGroup -Label "Winget ID:" -id "AppID" -placeholder "Winget ID" -Value $SourceData.appID } } } #EndRegion '.\Public\New-PSUGUISourceWinget.ps1' 19 #Region '.\Public\New-PSUGUIUninstallEXE.ps1' 0 function New-PSUGUIUninstallEXE{ [cmdletbinding()] param( [Parameter()][PSCustomObject]$SourceData ) New-UDElement -Tag "table" -Attributes @{ "style" = @{ "width" = "100%"; } "cellpadding" = "1" } -Content { New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Setup Name:" -id "Uninstall_installer" -placeholder "### Only set if not the same download file ###" -item_width 80 -item_colspan 3 -Value $SourceData.installer } New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Parameters:" -id "Uninstall_argumentList" -placeholder "Parameters" -item_width 80 -item_colspan 3 -Value $SourceData.argumentList } New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Conflicting Processes (Start):" -id "Uninstall_conflictingProcessStart" -placeholder "Comma seperated list of conflicting processes" -item_width 80 -item_colspan 3 -Value ($SourceData.conflictingProcessStart -Join ", ") } New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Conflicting Processes (End):" -id "Uninstall_conflictingProcessEnd" -placeholder "Comma seperated list of conflicting processes" -item_width 80 -item_colspan 3 -Value ($SourceData.conflictingProcessEnd -Join ", ") } New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Ignore Exit Codes:" -id "Uninstall_ignoreExitCodes" -placeholder "Comma seperated list of exit codes to ignore" -item_width 80 -item_colspan 3 -Value ($SourceData.ignoreExitCodes -Join ", ") } New-UDElement -Tag "tr" -Content { New-PSUGUISwitch -Label "WIM:" -id "Uninstall_wim" -Checked:$SourceData.wim New-PSUGUISwitch -Label "Packaged File (Dirfiles):" -id "Uninstall_dirFiles" -Checked:$SourceData.dirFiles } New-UDElement -Tag "tr" -Content { New-PSUGUISwitch -Label "Secure Argument List:" -id "Uninstall_secureArgumentList" -Checked:$SourceData.secureArgumentList } } } #EndRegion '.\Public\New-PSUGUIUninstallEXE.ps1' 37 #Region '.\Public\New-PSUGUIUninstallGUID.ps1' 0 function New-PSUGUIUninstallGUID{ [cmdletbinding()] param( [Parameter()][PSCustomObject]$SourceData ) New-UDElement -Tag "table" -Attributes @{ "style" = @{ "width" = "100%"; } "cellpadding" = "1" } -Content { New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Product Code:" -id "Uninstall_productCode" -placeholder "MSI Product Code" -item_width 80 -item_colspan 3 -Value $SourceData.productCode } } } #EndRegion '.\Public\New-PSUGUIUninstallGUID.ps1' 18 #Region '.\Public\New-PSUGUIUninstallMSI.ps1' 0 function New-PSUGUIUninstallMSI{ [cmdletbinding()] param( [Parameter()][PSCustomObject]$SourceData ) New-UDElement -Tag "table" -Attributes @{ "style" = @{ "width" = "100%"; } "cellpadding" = "1" } -Content { New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Setup Name:" -id "Uninstall_installer" -placeholder "### Only set if not the same download file ###" -item_width 80 -item_colspan 3 -Value $SourceData.installer } New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Parameters:" -id "Uninstall_additionalArgumentList" -placeholder "Parameters" -item_width 80 -item_colspan 3 -Value $SourceData.additionalArgumentList } New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Conflicting Processes (Start):" -id "Uninstall_conflictingProcessStart" -placeholder "Comma seperated list of conflicting processes" -item_width 80 -item_colspan 3 -Value ($SourceData.conflictingProcessStart -Join ", ") } New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Conflicting Processes (End):" -id "Uninstall_conflictingProcessEnd" -placeholder "Comma seperated list of conflicting processes" -item_width 80 -item_colspan 3 -Value ($SourceData.conflictingProcessEnd -Join ", ") } New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Ignore Exit Codes:" -id "Uninstall_ignoreExitCodes" -placeholder "Comma seperated list of exit codes to ignore" -item_width 80 -item_colspan 3 -Value ($SourceData.ignoreExitCodes -Join ", ") } New-UDElement -Tag "tr" -Content { New-PSUGUISwitch -Label "WIM:" -id "Uninstall_wim" -Checked:$SourceData.wim New-PSUGUISwitch -Label "Packaged File (Dirfiles):" -id "Uninstall_dirFiles" -Checked:$SourceData.dirFiles } New-UDElement -Tag "tr" -Content { New-PSUGUISwitch -Label "Secure Argument List:" -id "Uninstall_secureArgumentList" -Checked:$SourceData.secureArgumentList } } } #EndRegion '.\Public\New-PSUGUIUninstallMSI.ps1' 37 #Region '.\Public\New-PSUGUIUninstallName.ps1' 0 function New-PSUGUIUninstallName{ [cmdletbinding()] param( [Parameter()][PSCustomObject]$SourceData ) New-UDElement -Tag "table" -Attributes @{ "style" = @{ "width" = "100%"; } "cellpadding" = "1" } -Content { New-UDElement -Tag "tr" -Content { New-PSUGUIInputTextGroup -Label "Name:" -id "Uninstall_name" -placeholder "Name of Application" -item_width 80 -item_colspan 3 -Value $SourceData.name } } } #EndRegion '.\Public\New-PSUGUIUninstallName.ps1' 18 #Region '.\Public\New-PSUGUIUninstallScript.ps1' 0 function New-PSUGUIUninstallScript{ [cmdletbinding()] param( [Parameter()][PSCustomObject]$SourceData ) New-UDElement -Tag "table" -Attributes @{ "style" = @{ "width" = "100%"; } "cellpadding" = "1" } -Content { New-UDElement -Tag "tr" -Content { New-PSUGUIInputCode -id "Uninstall_Script" -item_colspan 4 -Code $SourceData.Script } } } #EndRegion '.\Public\New-PSUGUIUninstallScript.ps1' 18 #Region '.\Public\Publish-AppFactoryAppInstall.ps1' 0 function Publish-AppFactoryAppInstall { [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][PSCustomObject]$application, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) $installScript = [System.Collections.Generic.List[String]]@() $installScript.Add(" ## <Perform Installation tasks here>") | Out-Null if ($application.install.Type -eq "None") { return } $script:installerPath = "`$adtSession.dirFiles" #region Preinstall if ($application.install.conflictingProcessStart) { $params = @{ interactive = $true blockingProcess = $application.install.conflictingProcessStart deferCount = 3 LogLevel = $LogLevel } foreach ($line in $((Add-AppFactoryApplicationBlockingProcess @params -LogLevel $LogLevel).SyncRoot)) { $installScript.Add($line) } } #endregion #region WimMount if ($application.install.wim) { $mountPath = Join-Path -Path "$($ENV:ALLUSERSPROFILE)" -ChildPath "AFS" -AdditionalChildPath $application.Information.AppFolderName $script:installerPath = "`$mountPath" foreach ($line in $((Add-AppFactoryAppWIM -section "start" -MountPath $mountPath -LogLevel $LogLevel).SyncRoot)) { $installScript.Add($line) } } #endregion #region Install Script if($application.install.installer -ne "===SETUPFILENAME==="){ $setup_install = $application.install.installer } else{ $setup_install = $application.SourceFiles.AppSetupFileName } $params = @{ directory = $script:installerPath AppSetupFileName = $setup_install argumentList = $application.install.argumentList secureArgumentList = $application.install.secureArgumentList SuccessExitCodes = $application.install.SuccessExitCodes rebootExitCodes = $application.install.rebootExitCodes ignoreExitCodes = $application.install.ignoreExitCodes LogLevel = $LogLevel } switch ($application.install.type) { "EXE" { foreach ($line in $((Add-AppFactoryAppEXE @params).SyncRoot)) { $installScript.Add($line) } } "MSI" { $params.add("Transforms", $application.install.Transforms) $params.add("Action", "Install") $params.add("additionalArgumentList", $application.install.additionalArgumentList) $params.add("SkipMSIAlreadyInstalledCheck", $application.Install.SkipMSIAlreadyInstalledCheck) foreach ($line in $((Add-AppFactoryAppMSI @params).SyncRoot)) { $installScript.Add($line) } } "Script" { foreach($line in $application.Install.script){ $installScript.Add("`t$($line)") | Out-Null } } "PowerShell" { $installScript.Add("`tExecute-Process -Path `"powershell.exe`" -Parameters `"-ExecutionPolicy Bypass -File `"`"`$($($script:installerPath))\$($application.Install.script)`"`"`"") | Out-Null } "ECNO" { $installScript.Add("`tPush-Location $($script:installerPath)") | Out-Null $installScript.Add("`tStart-Process -FilePath powershell.exe -ArgumentList `"-ExecutionPolicy Bypass -File _action.ps1 install`" -NoNewWindow -Wait") | Out-Null $installScript.Add("`tPop-Location") | Out-Null } } #endregion #region WIM Dismount if ($application.install.wim) { foreach ($line in $(Add-AppFactoryAppWIM -section "end" -MountPath $mountPath -LogLevel $LogLevel).SyncRoot) { $installScript.Add($line) } } #endregion #region Postinstall if ($application.install.conflictingProcessEnd) { $params = @{ interactive = $false blockingProcess = $application.install.conflictingProcessEnd LogLevel = $LogLevel } foreach ($line in $((Add-AppFactoryApplicationBlockingProcess @params -LogLevel $LogLevel).SyncRoot)) { $installScript.Add($line) } } #endregion #C:\DevOps\ApplicationFactoryApplications\Workspace\Publish\7-Zip\Invoke-AppDeployToolkit.ps1 $publishPath = Join-Path -Path $script:AppFactoryWorkspace -ChildPath "Publish" -AdditionalChildPath $application.Information.AppFolderName $publishFile = Join-Path -Path $publishPath -ChildPath "Invoke-AppDeployToolkit.ps1" $outputFile = Get-Content -Path $publishFile $outputFile -replace " ## <Perform Installation tasks here>",$($installScript -join "`r`n") | Set-Content -Path $publishFile return } #EndRegion '.\Public\Publish-AppFactoryAppInstall.ps1' 110 #Region '.\Public\Publish-AppFactoryAppUninstall.ps1' 0 function Publish-AppFactoryAppUninstall{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][PSCustomObject]$application, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) $uninstallScript = [System.Collections.Generic.List[String]]@() $uninstallScript.Add(" ## <Perform Uninstallation tasks here>") | Out-Null if ($application.Uninstall.Type -eq "None") { return } if($application.Uninstall.dirFiles -or $application.Uninstall.type -eq "ECNO"){ $script:uninstallerPath = "`$adtSession.dirFiles" } else{ $script:uninstallerPath = "" } #region Preinstall if ($application.Uninstall.conflictingProcessStart) { $params = @{ interactive = $true blockingProcess = $application.Uninstall.conflictingProcessStart deferCount = 3 LogLevel = $LogLevel } foreach ($line in $((Add-AppFactoryApplicationBlockingProcess @params -LogLevel $LogLevel).SyncRoot)) { $uninstallScript.Add($line) } } #endregion #region WimMount if ($application.Uninstall.wim) { $mountPath = Join-Path -Path "$($ENV:ALLUSERSPROFILE)" -ChildPath "AFS" -AdditionalChildPath $application.Information.AppFolderName $script:uninstallerPath = "`$mountPath" foreach ($line in $((Add-AppFactoryAppWIM -section "start" -MountPath $mountPath -LogLevel $LogLevel).SyncRoot)) { $uninstallScript.Add($line) } } #endregion #region Uninstall Script if($application.Uninstall.installer -ne "===SETUPFILENAME==="){ $setup_uninstall = $application.Uninstall.installer } else{ $setup_uninstall = $application.SourceFiles.AppSetupFileName } $params = @{ directory = $script:uninstallerPath AppSetupFileName = $setup_uninstall argumentList = $application.Uninstall.argumentList secureArgumentList = $application.Uninstall.secureArgumentList SuccessExitCodes = $application.Uninstall.SuccessExitCodes rebootExitCodes = $application.Uninstall.rebootExitCodes ignoreExitCodes = $application.Uninstall.ignoreExitCodes LogLevel = $LogLevel } switch ($application.Uninstall.type) { "MSI" { $params.add("Transforms", $application.Uninstall.Transforms) $params.add("Action", "Uninstall") $params.add("additionalArgumentList", $application.Uninstall.additionalArgumentList) foreach ($line in $((Add-AppFactoryAppMSI @params).SyncRoot)) { $uninstallScript.Add($line) } } "EXE" { foreach ($line in $((Add-AppFactoryAppEXE @params).SyncRoot)) { $uninstallScript.Add($line) } } "Name" { $execute = "Uninstall-ADTApplication -Name `"$($application.Uninstall.name)`"" if($application.Uninstall.filterScript){$execute = "$($execute) -filterScript `{$($application.Uninstall.filterScript)`}"} $uninstallScript.Add("`t$($execute)") | Out-Null } "GUID" { $uninstallScript.Add("`tUninstall-ADTApplication -ProductCode '$($application.Uninstall.productCode)'") | Out-Null } "ECNO" { $uninstallScript.Add("`tPush-Location $($script:uninstallerPath)") | Out-Null $uninstallScript.Add("`tStart-Process -FilePath powershell.exe -ArgumentList `"-ExecutionPolicy Bypass -File _action.ps1 remove`" -NoNewWindow -Wait") | Out-Null $uninstallScript.Add("`tPop-Location") | Out-Null } "Script" { foreach($line in $application.Uninstall.script){ $uninstallScript.Add("`t$($line)") | Out-Null } } } #endregion #region WIM Dismount if ($application.Uninstall.wim) { foreach ($line in $(Add-AppFactoryAppWIM -section "end" -MountPath $mountPath -LogLevel $LogLevel).SyncRoot) { $uninstallScript.Add($line) } } #endregion #region Postinstall if ($application.Uninstall.conflictingProcessEnd) { $params = @{ interactive = $false blockingProcess = $application.Uninstall.conflictingProcessEnd LogLevel = $LogLevel } foreach ($line in $((Add-AppFactoryApplicationBlockingProcess @params -LogLevel $LogLevel).SyncRoot)) { $uninstallScript.Add($line) } } #endregion $publishPath = Join-Path -Path $script:AppFactoryWorkspace -ChildPath "Publish" -AdditionalChildPath $application.Information.AppFolderName $publishFile = Join-Path -Path $publishPath -ChildPath "Invoke-AppDeployToolkit.ps1" $outputFile = Get-Content -Path $publishFile $outputFile -replace " ## <Perform Uninstallation tasks here>",$($uninstallScript -join "`r`n") | Set-Content -Path $publishFile return } #EndRegion '.\Public\Publish-AppFactoryAppUninstall.ps1' 116 #Region '.\Public\Publish-AppFactoryClientApp.ps1' 0 function Publish-AppFactoryClientApp { [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][PSCustomObject]$application, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) if ($script:AppFactoryClientLogging) { Write-PSFMessage -Message "[<c='green'>$($application.IntuneAppName)</c>] Publishing Application" -Level $LogLevel -Tag "Applications", "Intune", "$($application.IntuneAppName)" -Target "Application Factory Client" } # Get configuration details for application $ApplicationFolder = Join-Path -Path $script:AppFactoryClientWorkspace -ChildPath "Downloads" -AdditionalChildPath $application.IntuneAppName $ApplicationConfig = Get-Content -Path (Join-Path -Path $ApplicationFolder -ChildPath "App.json") | ConvertFrom-JSON -Depth 5 # Configure Requirement Rule $RequirementRule = New-AppFactoryClientRequirementRule -application $ApplicationConfig -LogLevel $LogLevel # Configure Detection Rule $DetectionRules = New-AppFactoryClientDetectionRule -application $ApplicationConfig -applicationFolder $ApplicationFolder -LogLevel $LogLevel # Create the base 64 image file $Icon = [System.Convert]::ToBase64String([System.IO.File]::ReadAllBytes("$(Join-Path -Path $ApplicationFolder -ChildPath $ApplicationConfig.PackageInformation.IconFile)")) $IntuneAppPackage = Get-ChildItem "$($ApplicationFolder)\*.intunewin" $Win32AppArgs = @{ "FilePath" = $IntuneAppPackage.FullName "DisplayName" = "$($script:AppFactoryClientPrefix)$($application.IntuneAppName) $($application.AppVersion)" "AppVersion" = $ApplicationConfig.Information.AppVersion "Publisher" = $ApplicationConfig.Information.Publisher "InstallExperience" = $ApplicationConfig.Program.InstallExperience "RestartBehavior" = $ApplicationConfig.Program.DeviceRestartBehavior "DetectionRule" = $DetectionRules "RequirementRule" = $RequirementRule "Notes" = "$($ApplicationConfig.Information.Notes)`n`rSTSID:$($application.GUID)" } # Dynamically add additional parameters for Win32 app if (-not([string]::IsNullOrEmpty($ApplicationConfig.Information.Description))) { $Win32AppArgs.Add("Description", $ApplicationConfig.Information.Description) } else{ $Win32AppArgs.Add("Description", $Win32AppArgs.DisplayName) } if ($null -ne $RequirementRules) { $Win32AppArgs.Add("AdditionalRequirementRule", $RequirementRules) } if (Test-Path -Path (Join-Path -Path $ApplicationFolder -ChildPath $ApplicationConfig.PackageInformation.IconFile)) { $Win32AppArgs.Add("Icon", $Icon) } if (-not([string]::IsNullOrEmpty($ApplicationConfig.Information.InformationURL))) { $Win32AppArgs.Add("InformationURL", $ApplicationConfig.Information.InformationURL) } if (-not([string]::IsNullOrEmpty($ApplicationConfig.Information.PrivacyURL))) { $Win32AppArgs.Add("PrivacyURL", $ApplicationConfig.Information.PrivacyURL) } if (-not([string]::IsNullOrEmpty($ApplicationConfig.Information.Owner))) { $Win32AppArgs.Add("Owner", $ApplicationConfig.Information.Owner) } if (-not([string]::IsNullOrEmpty($ApplicationConfig.Program.InstallCommand))) { if($application.InteractiveInstall){ $Win32AppArgs.Add("InstallCommandLine", $ApplicationConfig.Program.InstallCommandInteractive) } else{ $Win32AppArgs.Add("InstallCommandLine", $ApplicationConfig.Program.InstallCommand) } } if (-not([string]::IsNullOrEmpty($ApplicationConfig.Program.UninstallCommand))) { if($application.InteractiveUninstall){ $Win32AppArgs.Add("UninstallCommandLine", $ApplicationConfig.Program.UninstallCommandInteractive) } else{ $Win32AppArgs.Add("UninstallCommandLine", $ApplicationConfig.Program.UninstallCommand) } } if (-not([string]::IsNullOrEmpty($ApplicationConfig.Program.AllowAvailableUninstall))) { if ($ApplicationConfig.Program.AllowAvailableUninstall -eq $true) { $Win32AppArgs.Add("AllowAvailableUninstall", $true) } } try{ Remove-Variable -Scope Global -Name AccessToken -ErrorAction SilentlyContinue -Force Connect-MSIntuneGraph -TenantID $script:AppFactoryClientTenantID -ClientID $script:AppFactoryClientClientID -ClientSecret $script:AppFactoryClientAppRegSecret | Out-Null $Application = Add-IntuneWin32App @Win32AppArgs -UseAzCopy -ErrorAction Stop -WarningAction Stop return $Application } catch{ $intuneApp = Get-GraphIntuneApp -displayName $application.IntuneAppName if ($intuneApp.count -gt 1) { $intuneApp = $intuneApp | Sort-Object -Property createdDateTime -Descending | Select-Object -First 1 } Remove-GraphIntuneApp -applicationid $intuneApp.id throw $_ } } #EndRegion '.\Public\Publish-AppFactoryClientApp.ps1' 89 #Region '.\Public\Publish-AppFactoryIntunePackage.ps1' 0 function Publish-AppFactoryIntunePackage { [CmdletBinding()] [OutputType([System.Collections.Generic.List[PSCustomObject]])] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][System.Collections.Generic.List[PSCustomObject]]$applicationList, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) # Create a list to store the results of the process $applications = [System.Collections.Generic.List[PSCustomObject]]@() foreach ($application in $applicationList) { try { # Check what Azure Storage Containers we should be uploading the files to $containerUploads = [System.Collections.Generic.List[PSCustomObject]]@() if ((($application.SourceFiles.PublishTo.getType()).BaseType.Name -eq "Array" -and $application.SourceFiles.publishTo.Count -gt 0) -or (($application.SourceFiles.PublishTo.getType()).BaseType.Name -eq "Object" -and $application.SourceFiles.publishTo.length -gt 1)) { foreach ($org in $application.SourceFiles.PublishTo) { $containerUploads.Add($org) | Out-Null } } else { $containerUploads.Add($script:AppFactoryPublicFolder) | Out-Null } # File Upload Details $SourceFolder = Join-Path -Path $script:AppFactoryWorkspace -ChildPath "Publish" -AdditionalChildPath $application.Information.AppFolderName $applicationJSON = $application.PSObject.Copy() $applicationJSON.PSObject.Properties.Remove("GUID") $applicationJSON.PSObject.Properties.Remove("SourceFiles") $applicationJSON.PSObject.Properties.Remove("Install") $applicationJSON.PSObject.Properties.Remove("Uninstall") $applicationJSONPath = Join-Path -Path $SourceFolder -ChildPath "App.json" if($applicationJSON.DetectionRule.KeyPath -match "###PRODUCTCODE###"){ $msi = Join-Path -Path $SourceFolder -ChildPath "files" -AdditionalChildPath $application.SourceFiles.AppSetupFileName $productCode = get-msiMetaData -path $msi -Property ProductCode $applicationJSON.DetectionRule[0].KeyPath = $applicationJSON.DetectionRule.KeyPath -replace "###PRODUCTCODE###",[regex]::Match($productCode,"{.*}").value } $applicationJSON | ConvertTo-JSON -Depth 10 | Out-File -Path $applicationJSONPath -Force # Application Files to Upload $ApplicationPath = Join-Path -Path $script:AppFactorySourceDir -ChildPath "Apps" -AdditionalChildPath $application.Information.AppFolderName $ScriptDataFile = Join-Path -Path $SourceFolder -ChildPath $application.DetectionRule.ScriptFile $AppIconFile = Join-Path -Path $ApplicationPath -ChildPath $application.PackageInformation.IconFile $IntunePackage = Join-Path -Path $SourceFolder -ChildPath $application.SourceFiles.IntunePackage $appUploads = [PSCustomObject]@( @{ "File" = $applicationJSONPath "Blob" = "$($application.GUID)/$($application.Information.AppVersion)/App.json" }, @{ "File" = $IntunePackage "Blob" = "$($application.GUID)/$($application.Information.AppVersion)/$($application.SourceFiles.IntunePackage)" }, @{ "File" = $AppIconFile "Blob" = "$($application.GUID)/$($application.Information.AppVersion)/$($application.PackageInformation.IconFile)" }, @{ "File" = $ScriptDataFile "Blob" = "$($application.GUID)/$($application.Information.AppVersion)/detection.ps1" } ) # Process the uploads for each of the files as required to each container that is required foreach ($container in $containerUploads) { if ($script:AppFactoryLogging) { Write-PSFMessage -Message "[<c='green'>$($application.Information.DisplayName)</c>] Uploading files to storage" -Level $LogLevel -Tag "Application", "$($application.Information.DisplayName)" -Target "Application Factory Service" } foreach ($upload in $appUploads) { if ((Test-Path $upload.File) -and (Get-Item $upload.File).Attributes[0] -ne "Directory") { try { if ($script:AppFactoryLogging) { Write-PSFMessage -Message "[<c='green'>$($application.Information.DisplayName)</c>)] Uploading <c='green'>$($upload.File)</c> to <c='green'>$($container)</c> container" -Level $LogLevel -Tag "Application", "$($application.Information.DisplayName)" -Target "Application Factory Service" } Set-AzStorageBlobContent @upload -Container $container -Context $script:psadtStorageContext -Force -ErrorAction Stop | Out-Null } catch { throw "[$($application.IntuneAppName)] Unable able to upload file: $($_.Exception.Message)" } } } } $application.SourceFiles.LastUpdate = (Get-Date).ToString("yyyy/MM/dd HH:mm:ss") $originalAppInfo = Get-Content -Path "$($ApplicationPath)\ApplicationConfig.json" | ConvertFrom-JSON $application.DetectionRule = $originalAppInfo.DetectionRule $application | ConvertTo-JSON -Depth 10 | Out-File -FilePath "$($ApplicationPath)\ApplicationConfig.json" -Force $applications.Add($application) } catch { if ($script:AppFactoryLogging) { Write-PSFMessage -Message "[<c='green'>$($application.Information.DisplayName)</c>] Failed to upload intune file" -Level "Error" -Tag "Application", "$($application.Information.DisplayName)" -Target "Application Factory Service" } throw $_ } } return $applications } #EndRegion '.\Public\Publish-AppFactoryIntunePackage.ps1' 94 #Region '.\Public\Remove-AppFactoryApp.ps1' 0 function Remove-AppFactoryApp{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$appGUID, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) # Get the application Config $configfile = Get-AppFactoryApp -appGUID $appGUID -LogLevel $LogLevel if (-not ($configfile)) { throw "Application with GUID $($appGUID) does not exist." } # Get the application folder $ApplicationFolder = Join-Path -Path $script:AppFactorySourceDir -ChildPath "Apps" -AdditionalChildPath $configfile.Information.AppFolderName # Remove the folder try{ Remove-Item -Path $ApplicationFolder -Recurse -Force | Out-Null Write-PSFMessage -Message "[$($configfile.Information.DisplayName)] Removed Configuration Files at path $($ApplicationFolder)" -Level $LogLevel -Tag "Application","$($appGUID)","$($configfile.Information.DisplayName)" -Target "Application Factory Service" } catch{ Write-PSFMessage -Message "Error Encountered: $($_)" -Level "Error" -Tag "Application","$($appGUID)","$($configfile.Information.DisplayName)" -Target "Application Factory Service" throw $_ } } #EndRegion '.\Public\Remove-AppFactoryApp.ps1' 24 #Region '.\Public\Remove-AppFactoryClientApp.ps1' 0 function Remove-AppFactoryClientApp { [CmdletBinding()] [OutputType([System.Collections.Generic.List[PSCustomObject]])] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][PSCustomObject]$application, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][System.Collections.Generic.List[PSCustomObject]]$intuneApplications, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) # Loop through the applications and remove ones that are no longer required if ($script:AppFactoryClientLogging) { Write-PSFMessage -Message "[<c='green'>$($application.IntuneAppName)</c>] Removing Previous Applications" -Level $LogLevel -Tag "Applications", "Intune", "$($application.IntuneAppName)" -Target "Application Factory Client" } $applications = $intuneApplications | Where-Object { $_.Notes -match "STSID:$($application.GUID)" } | Select-Object id, displayname, @{Label = "Version"; expression = { [version]$_.displayversion } } | Sort-Object -Property "Version" $keepApplications = 0 if($application.KeepPrevious){ $keepApplications = $application.KeepPrevious } if ($applications.count -gt $($keepApplications)) { $removalCount = $applications.count - $keepApplications if ($script:AppFactoryClientLogging) { Write-PSFMessage -Message "[<c='green'>$($application.IntuneAppName)</c>] Based on keeping $($keepApplications) previous versions there are $($removalCount) applications to remove." -Level $LogLevel -Tag "Applications", "Intune", "$($application.IntuneAppName)" -Target "Application Factory Client" } for ($i = 0; $i -lt $removalCount; $i++) { Remove-GraphIntuneApp -applicationid $applications[$i].id } } else { if ($script:AppFactoryClientLogging) { Write-PSFMessage -Message "[<c='green'>$($application.IntuneAppName)</c>] Based on keeping $($keepApplications) previous versions there are no applications to remove." -Level $LogLevel -Tag "Applications", "Intune", "$($application.IntuneAppName)" -Target "Application Factory Client" } } } #EndRegion '.\Public\Remove-AppFactoryClientApp.ps1' 33 #Region '.\Public\Remove-AppFactoryClientAppFiles.ps1' 0 function Remove-AppFactoryClientAppFiles{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][PSCustomObject]$applications, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) $downloadFolder = Join-Path -Path $script:AppFactoryClientWorkspace -ChildPath "Downloads" -AdditionalChildPath $application.IntuneAppName try{ Remove-Item -Path $downloadFolder -Force -Recurse -Confirm:$false if($script:AppFactoryClientLogging){ Write-PSFMessage -Message "[<c='green'>$($application.IntuneAppName)</c>] Removed files." -Level $LogLevel -Tag "Applications","$($application.IntuneAppName)" -Target "Application Factory Client" } } catch{ if($script:AppFactoryClientLogging){ Write-PSFMessage -Message "[<c='green'>$($application.IntuneAppName)</c>] Unable to delete files. Error: $($_)" -Level Error -Tag "Applications","$($application.IntuneAppName)" -Target "Application Factory Client" } throw $_ } } #EndRegion '.\Public\Remove-AppFactoryClientAppFiles.ps1' 21 #Region '.\Public\Remove-AppFactoryProcessFiles.ps1' 0 function Remove-AppFactoryProcessFiles{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][PSCustomObject]$applicationList, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) foreach($application in $applicationList){ $installersPath = Join-Path -Path $script:AppFactoryWorkspace -ChildPath "Installers" -AdditionalChildPath $application.Information.AppFolderName $publishPath = Join-Path -Path $script:AppFactoryWorkspace -ChildPath "Publish" -AdditionalChildPath $application.Information.AppFolderName Remove-Item -path $installersPath -Recurse -Force -Confirm:$false if ($script:AppFactoryLogging) { Write-PSFMessage -Message "[<c='green'>$($application.Information.DisplayName)</c>] Application Installer Folder Removed [<c='green'>$($installersPath)</c>]." -Level "Output" -Tag "Process",$application.Information.DisplayName -Target "Application Factory Service" } Remove-Item -path $publishPath -Recurse -Force -Confirm:$false if ($script:AppFactoryLogging) { Write-PSFMessage -Message "[<c='green'>$($application.Information.DisplayName)</c>] Application Publish Folder Removed [<c='green'>$($publishPath )</c>]." -Level "Output" -Tag "Process",$application.Information.DisplayName -Target "Application Factory Service" } } } #EndRegion '.\Public\Remove-AppFactoryProcessFiles.ps1' 20 #Region '.\Public\Remove-AppFactoryServiceAppVersions.ps1' 0 function Remove-AppFactoryServiceAppVersions{ [CmdletBinding()] [OutputType([System.Collections.Generic.List[Version]])] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$appGUID, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$version, [Parameter()][ValidateNotNullOrEmpty()][PSCustomObject[]]$AllAppList, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) if (-not $PSBoundParameters.ContainsKey("AllAppList")){ $AllAppList = $script:PublishedAppList } foreach($key in $AllAppList.GetEnumerator().keys){ $container = $AllAppList.$($key) $blobs = $container | Where-Object { $_.Name -like "$($appGUID)/$($version)/*" } foreach($blob in $blobs){ Remove-AzStorageBlob -Blob $blob.name -Container $key -Context $script:psadtStorageContext -Force } } } #EndRegion '.\Public\Remove-AppFactoryServiceAppVersions.ps1' 21 #Region '.\Public\Remove-AppFactoryServiceClient.ps1' 0 function Remove-AppFactoryServiceClient{ [CmdletBinding()] param( [Alias("GUID")][Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$clientGUID, [Parameter()][ValidateSet("Output","Verbose")][string]$LogLevel = "Verbose" ) # Get Client Configuration Files $client = Get-AppFactoryServiceClient -GUID $clientGUID -LogLevel $LogLevel if ($null -eq $client) { Write-PSFMessage -Message "Error Encountered: Client not found." -Level "Error" -Tag "Client","$($clientGUID)" -Target "Application Factory Service" throw "CLient not found." } try{ $clientStorageContainerContext = Connect-AppFactoryAzureStorage -storageContainer $script:AppFactoryDeploymentsContainer -storageSecret $script:AppFactoryDeploymentsSecret # Remove Azure Storage Container Remove-AzStorageContainer -Name $clientGUID -Context $clientStorageContainerContext -Force -ErrorAction Stop if($script:AppFactoryLogging){ Write-PSFMessage -Message "[$($client.Name)] Removed Azure Container" -Level $LogLevel -Tag "Clients","ContactList","$($client.Name)","$($clientGUID)" -Target "Application Factory Service" } # Remove Configuration File. $fileName = Join-Path -Path $script:AppFactorySourceDir -ChildPath "Clients" -AdditionalChildPath $client.fileName Remove-Item -Path $fileName -Force if($script:AppFactoryLogging){ Write-PSFMessage -Message "[$($client.Name)] Removed configuration file" -Level $LogLevel -Tag "Clients","ContactList","$($client.Name)","$($clientGUID)" -Target "Application Factory Service" } } catch{ Write-PSFMessage -Message "Error Encountered: $($_)" -Level "Error" -Tag "Clients","ContactList","$($client.Name)","$($clientGUID)" -Target "Application Factory Service" throw $_ } } #EndRegion '.\Public\Remove-AppFactoryServiceClient.ps1' 32 #Region '.\Public\Set-AppFactoryApp.ps1' 0 function Set-AppFactoryApp { [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][String]$appGUID, [Parameter()][ValidateNotNullOrEmpty()][String]$displayName, [Parameter()][string]$AppVersion, [Parameter()][ValidateNotNullOrEmpty()][String]$AppFolderName, [Parameter()][ValidateNotNullOrEmpty()][String]$description, [Parameter()][ValidateNotNullOrEmpty()][String]$publisher, [Parameter()][String]$notes = "", [Parameter()][String]$owner = "", [Parameter()][String]$informationURL = "", [Parameter()][String]$privacyURL = "", [Parameter()][ValidateSet("StorageAccount", "Sharepoint", "Winget", "Evergreen", "PSADT", "ECNO", "LocalStorage")][String]$AppSource, [Parameter()][ValidateNotNullOrEmpty()][string]$appID, [Alias("appSetupName")][Parameter()][ValidateNotNullOrEmpty()][string]$AppSetupFileName = "", [Alias("storageContainerName")][Parameter()][ValidateNotNullOrEmpty()][string]$StorageAccountContainerName = "", [Parameter()][String[]]$ExtraFiles = @(), [Parameter()][PSCustomObject]$filterOptions = @{}, [Parameter()][String[]]$publishTo = @(), [Parameter()][String[]]$AvailableVersions = @(), [Parameter()][ValidateSet("system", "user")][string]$InstallExperience = "system", [Parameter()][ValidateSet("suppress", "force", "basedOnReturnCode", "allow")][string]$DeviceRestartBehavior = "suppress", [Parameter()][ValidateSet("true", "false")][string]$AllowAvailableUninstall = $true, [Parameter()][ValidateSet("W10_1607", "W10_1703", "W10_1709", "W10_1809", "W10_1909", "W10_2004", "W10_20H2", "W10_21H1", "W10_21H2", "W10_22H2", "W11_21H2", "W11_22H2")][string]$MinimumSupportedWindowsRelease = "W10_1607", [Parameter()][ValidateSet("All", "x64", "x86")][string]$Architecture = "All", [Parameter()][String[]]$DependsOn = @(), [Parameter()][bool]$active, [Parameter()][bool]$pauseUpdate, [Parameter()][switch]$force, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) # Get the application Config $configfile = Get-AppFactoryApp -appGUID $appGUID -LogLevel $LogLevel if (-not ($configfile)) { throw "Application with GUID $($GUID) does not exist." } # Take note of the original name in case we are changing it $originalFolderName = $configfile.Information.AppFolderName # Update the config file with the new values if ($PSBoundParameters.ContainsKey("AppFolderName")) { $configfile.Information.AppFolderName = $AppFolderName $originalPath = Join-Path -Path $script:AppFactorySourceDir -ChildPath "Apps" -AdditionalChildPath $originalFolderName Rename-Item -Path $originalPath -NewName $AppFolderName } if ($PSBoundParameters.ContainsKey("displayName")) { $configfile.Information.DisplayName = $displayName } if ($PSBoundParameters.ContainsKey("AppVersion")) { $configfile.Information.AppVersion = $AppVersion } if ($PSBoundParameters.ContainsKey("description")) { $configfile.Information.Description = $Description } if ($PSBoundParameters.ContainsKey("publisher")) { $configfile.Information.Publisher = $Publisher } if ($PSBoundParameters.ContainsKey("notes")) { $configfile.Information.Notes = $Notes } if ($PSBoundParameters.ContainsKey("owner")) { $configfile.Information.owner = $owner } if ($PSBoundParameters.ContainsKey("informationURL")) { $configfile.Information.informationURL = $informationURL } if ($PSBoundParameters.ContainsKey("privacyURL")) { $configfile.Information.PrivacyURL = $PrivacyURL } if ($PSBoundParameters.ContainsKey("AppSource")) { $configfile.SourceFiles.AppSource = $AppSource } if ($PSBoundParameters.ContainsKey("appID")) { $configfile.SourceFiles.AppID = $AppID } if ($PSBoundParameters.ContainsKey("AppSetupFileName")) { $configfile.SourceFiles.AppSetupFileName = $AppSetupFileName } if ($PSBoundParameters.ContainsKey("StorageAccountContainerName")) { $configfile.SourceFiles.StorageAccountContainerName = $StorageAccountContainerName } if ($PSBoundParameters.ContainsKey("ExtraFiles")) { $configfile.SourceFiles.ExtraFiles = $ExtraFiles } if ($PSBoundParameters.ContainsKey("filterOptions")) { $configfile.SourceFiles.FilterOptions = $FilterOptions } if ($PSBoundParameters.ContainsKey("publishTo")) { $configfile.SourceFiles.publishTo = $publishTo } if ($PSBoundParameters.ContainsKey("AvailableVersions")) {$configfile.SourceFiles.AvailableVersions = $AvailableVersions } if ($PSBoundParameters.ContainsKey("InstallExperience")) { $configfile.Program.InstallExperience = $InstallExperience } if ($PSBoundParameters.ContainsKey("DeviceRestartBehavior")) { $configfile.Program.DeviceRestartBehavior = $DeviceRestartBehavior } if ($PSBoundParameters.ContainsKey("AllowAvailableUninstall")) { $configfile.Program.AllowAvailableUninstall = $AllowAvailableUninstall } if ($PSBoundParameters.ContainsKey("MinimumSupportedWindowsRelease")) { $configfile.RequirementRule.MinimumSupportedWindowsRelease = $MinimumSupportedWindowsRelease } if ($PSBoundParameters.ContainsKey("Architecture")) { $configfile.RequirementRule.Architecture = $Architecture } if ($PSBoundParameters.ContainsKey("active")) { $configfile.SourceFiles.Active = $Active } if ($PSBoundParameters.ContainsKey("pauseUpdate")) { $configfile.SourceFiles.pauseUpdate = $pauseUpdate } if ($PSBoundParameters.ContainsKey("DependsOn")) { if ($null -ne $DepandsOn -and $DepandsOn -ne "") { foreach ($app in $DependsOn) { $exists = Get-AppFactoryApp -appGUID $app if ($null -eq $exists) { Write-PSFMessage -Message "Error Encountered: Dependent Application with GUID $($app) does not exist" -Level "Error" -Tag "Application", "$($originalDisplayName)", "$($appGUID)" -Target "Application Factory Service" throw "Dependent Application with GUID $($app) does not exist" } } } else { $configfile.SourceFiles.DependsOn = @() } } # Create the configuration for the application try{ Write-AppConfiguration -configfile $configfile -LogLevel $LogLevel } catch{ Write-PSFMessage -Message "Error Encountered: $($_)" -Level "Error" -Tag "Application", "$($displayName)", "$($configFIle.GUID)" -Target "Application Factory Service" throw $_ } return $configfile } #EndRegion '.\Public\Set-AppFactoryApp.ps1' 94 #Region '.\Public\Set-AppFactoryAppDetectionRule.ps1' 0 function Set-AppFactoryAppDetectionRule{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$appGUID, [Parameter(Mandatory = $true)][ValidateSet("MSI","Registry","Script")][string]$Type, [Parameter()][ValidateSet("notConfigured","equal","notEqual","greaterThanOrEqual","greaterThan","lessThanOrEqual","lessThan")][string]$ProductVersionOperator = "notConfigured", [Parameter()][ValidateSet("Existence","VersionComparison")][string]$DetectionMethod, [Parameter()][ValidateNotNullOrEmpty()][string]$KeyPath = "###PRODUCTCODE###", [Parameter()][ValidateNotNullOrEmpty()][string]$ValueName = "DisplayVersion", [Parameter()][ValidateSet("exists","notExists")][string]$DetectionType, [Parameter()][switch]$Check32BitOn64System = $false, [Parameter()][Switch]$EnforceSignatureCheck = $false, [Parameter()][Switch]$RunAs32Bit = $false, [Parameter()][ValidateSet("notConfigured","equal","notEqual","greaterThanOrEqual","greaterThan","lessThanOrEqual","lessThan")][string]$Operator = "greaterThanOrEqual", [Parameter()][ValidateNotNullOrEmpty()][string]$ScriptFile = "detection.ps1", [Parameter()][ValidateSet("Output","Verbose")][string]$LogLevel = "Verbose" ) # Get the application Config $configfile = Get-AppFactoryApp -appGUID $appGUID -LogLevel $LogLevel if (-not ($configfile)) { throw "Application with GUID $($GUID) does not exist." } # Create a object with the details for the detection type $detectionRule = [PSCustomObject]@{ "Type" = $Type } # Depending on the type, set the appropriate details switch($Type){ "MSI"{ $detectionRule | Add-Member -MemberType "NoteProperty" -Name "ProductCode" -Value "<replaced_by_pipeline>" $detectionRule | Add-Member -MemberType "NoteProperty" -Name "ProductVersionOperator" -Value $ProductVersionOperator if($ProductVersionOperator -ne "notConfigured"){ $detectionRule | Add-Member -MemberType "NoteProperty" -Name "ProductVersion" -Value "<replaced_by_pipeline>" } } "Registry"{ $detectionRule | Add-Member -MemberType "NoteProperty" -Name "DetectionMethod" -Value $DetectionMethod $detectionRule | Add-Member -MemberType "NoteProperty" -Name "KeyPath" -Value "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$($KeyPath)" $detectionRule | Add-Member -MemberType "NoteProperty" -Name "ValueName" -Value $ValueName if($DetectionType){ $detectionRule | Add-Member -MemberType "NoteProperty" -Name "DetectionType" -Value $DetectionType } if($Operator){ $detectionRule | Add-Member -MemberType "NoteProperty" -Name "Operator" -Value $Operator $detectionRule | Add-Member -MemberType "NoteProperty" -Name "Value" -Value "<replaced_by_pipeline>" } $detectionRule | Add-Member -MemberType "NoteProperty" -Name "Check32BitOn64System" -Value "$($Check32BitOn64System.IsPresent)" } "Script"{ $detectionRule | Add-Member -MemberType "NoteProperty" -Name "ScriptFile" -Value $ScriptFile $detectionRule | Add-Member -MemberType "NoteProperty" -Name "EnforceSignatureCheck" -Value "$($EnforceSignatureCheck.IsPresent)" $detectionRule | Add-Member -MemberType "NoteProperty" -Name "RunAs32Bit" -Value "$($RunAs32Bit.IsPresent)" $detectionScriptPath = Join-Path -Path $script:AppFactorySourceDir -ChildPath "Apps" -AdditionalChildPath $configfile.Information.AppFolderName,"detection.ps1" if(-not (Test-Path $detectionScriptPath)){ $detectiontemplate = Join-Path -Path $script:AppFactorySupportTemplateFolder -ChildPath "Application" -AdditionalChildPath "detection.ps1" Copy-Item -Path $detectiontemplate -Destination $detectionScriptPath } } } $configfile.DetectionRule = ,$detectionRule try{ Write-AppConfiguration -configfile $configfile -LogLevel $LogLevel } catch{ Write-PSFMessage -Message "Error Encountered: $($_)" -Level "Error" -Tag "Application", "$($configfile.Information.displayName)", "$($configFIle.GUID)" -Target "Application Factory Service" throw $_ } } #EndRegion '.\Public\Set-AppFactoryAppDetectionRule.ps1' 69 #Region '.\Public\Set-AppFactoryAppInstall.ps1' 0 function Set-AppFactoryAppInstall { [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$appGUID, [Parameter(Mandatory = $true)][ValidateSet("None","Script", "PowerShell", "ECNO", "EXE", "MSI")][string]$Type, [Parameter()][string]$argumentList, [Parameter()][string]$additionalArgumentList, [Parameter()][bool]$secureArgumentList, [Parameter()][int[]]$successExitCodes, [Parameter()][int[]]$rebootExitCodes, [Parameter()][int[]]$ignoreExitCodes, [Parameter()][String[]]$conflictingProcessStart, [Parameter()][String[]]$conflictingProcessEnd, [Parameter()][ValidateNotNullOrEmpty()][string]$installer, [Parameter()][ValidateNotNullOrEmpty()][string]$transforms, [Parameter()][bool]$SkipMSIAlreadyInstalledCheck, [Parameter()][string[]]$script, [Parameter()][bool]$wim, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) # Get the application Config $configfile = Get-AppFactoryApp -appGUID $appGUID -LogLevel $LogLevel if (-not ($configfile)) { throw "Application with GUID $($GUID) does not exist." } if ($PSBoundParameters.ContainsKey("type")) { $configfile.install.type = $type } if ($PSBoundParameters.ContainsKey("argumentList")) { $configfile.install.argumentList = $argumentList } if ($PSBoundParameters.ContainsKey("additionalArgumentList")) { $configfile.install.additionalArgumentList = $additionalArgumentList } if ($PSBoundParameters.ContainsKey("secureArgumentList")) { $configfile.install.secureArgumentList = $secureArgumentList } if ($PSBoundParameters.ContainsKey("successExitCodes")) { $configfile.install.successExitCodes = $successExitCodes } if ($PSBoundParameters.ContainsKey("rebootExitCodes")) { $configfile.install.rebootExitCodes = $rebootExitCodes } if ($PSBoundParameters.ContainsKey("ignoreExitCodes")) { $configfile.install.ignoreExitCodes = $ignoreExitCodes } if ($PSBoundParameters.ContainsKey("conflictingProcessStart")) { $configfile.install.conflictingProcessStart = $conflictingProcessStart } if ($PSBoundParameters.ContainsKey("conflictingProcessEnd")) { $configfile.install.conflictingProcessEnd = $conflictingProcessEnd } if ($PSBoundParameters.ContainsKey("installer")) { $configfile.install.installer = $installer } if ($PSBoundParameters.ContainsKey("transforms")) { $configfile.install.transforms = $transforms } if ($PSBoundParameters.ContainsKey("SkipMSIAlreadyInstalledCheck")) { $configfile.install.SkipMSIAlreadyInstalledCheck = $SkipMSIAlreadyInstalledCheck } if ($PSBoundParameters.ContainsKey("script")) { $configfile.install.script = $script -split "`n" } if ($PSBoundParameters.ContainsKey("wim")) { $configfile.install.wim = $wim } # Create the configuration for the application try{ Write-AppConfiguration -configfile $configfile -LogLevel $LogLevel } catch{ Write-PSFMessage -Message "Error Encountered: $($_)" -Level "Error" -Tag "Application", "$($configfile.Information.displayName)", "$($configFIle.GUID)" -Target "Application Factory Service" throw $_ } } #EndRegion '.\Public\Set-AppFactoryAppInstall.ps1' 49 #Region '.\Public\Set-AppFactoryAppUninstall.ps1' 0 function Set-AppFactoryAppUninstall { [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$appGUID, [Parameter(Mandatory = $true)][ValidateSet("None", "MSI", "EXE", "Name", "GUID", "ECNO", "Script", "Powershell")][string]$type, [Parameter()][string]$name, [Parameter()][ValidateSet('Contains','Exact','Wildcard','Regex')][string]$nameMatch, [Parameter()][string]$productCode, [Parameter()][string]$filterScript, [Parameter()][string]$argumentList, [Parameter()][string]$additionalArgumentList, [Parameter()][bool]$secureArgumentList, [Parameter()][string[]]$script, [Parameter()][string]$installer, [Parameter()][bool]$wim, [Parameter()][bool]$dirFiles, [Parameter()][int[]]$ignoreExitCodes, [Parameter()][String[]]$conflictingProcessStart, [Parameter()][String[]]$conflictingProcessEnd, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) # Get the application Config $configfile = Get-AppFactoryApp -appGUID $appGUID -LogLevel $LogLevel if (-not ($configfile)) { throw "Application with GUID $($GUID) does not exist." } if ($PSBoundParameters.ContainsKey("type")) { $configfile.Uninstall.type = $type } if ($PSBoundParameters.ContainsKey("name")) { $configfile.Uninstall.name = $name } if ($PSBoundParameters.ContainsKey("nameMatch")) { $configfile.Uninstall.nameMatch = $nameMatch } if ($PSBoundParameters.ContainsKey("productCode")) { $configfile.Uninstall.productCode = $productCode } if ($PSBoundParameters.ContainsKey("filterScript")) { $configfile.Uninstall.filterScript = $filterScript } if ($PSBoundParameters.ContainsKey("argumentList")) { $configfile.Uninstall.argumentList = $argumentList } if ($PSBoundParameters.ContainsKey("additionalArgumentList")) { $configfile.Uninstall.additionalArgumentList = $additionalArgumentList } if ($PSBoundParameters.ContainsKey("secureArgumentList")) { $configfile.Uninstall.secureArgumentList = $secureArgumentList } if ($PSBoundParameters.ContainsKey("script")) { $configfile.Uninstall.script = $script -split "`n" } if ($PSBoundParameters.ContainsKey("installer")) { $configfile.Uninstall.installer = $installer } if ($PSBoundParameters.ContainsKey("wim")) { $configfile.Uninstall.wim = $wim } if ($PSBoundParameters.ContainsKey("dirFiles")) { $configfile.Uninstall.dirFiles = $dirFiles } if ($PSBoundParameters.ContainsKey("ignoreExitCodes")) { $configfile.Uninstall.ignoreExitCodes = $ignoreExitCodes } if ($PSBoundParameters.ContainsKey("conflictingProcessStart")) { $configfile.Uninstall.conflictingProcessStart = $conflictingProcessStart } if ($PSBoundParameters.ContainsKey("conflictingProcessEnd")) { $configfile.Uninstall.conflictingProcessEnd = $conflictingProcessEnd } # Create the configuration for the application try{ Write-AppConfiguration -configfile $configfile -LogLevel $LogLevel } catch{ Write-PSFMessage -Message "Error Encountered: $($_)" -Level "Error" -Tag "Application", "$($configfile.Information.displayName)", "$($configFIle.GUID)" -Target "Application Factory Service" throw $_ } } #EndRegion '.\Public\Set-AppFactoryAppUninstall.ps1' 51 #Region '.\Public\Set-AppFactoryServiceClient.ps1' 0 <# .DESCRIPTION This cmdlet is designed to update the details of an client .PARAMETER GUID The unique identifier for the client that we want to work with .PARAMETER name The name of the client .PARAMETER contactList The list of contacts for the client .PARAMETER LogLevel If logging is enabled, what level of logging do we want, default is verbose. .EXAMPLE Update an client name Set-AppFactoryClient -clientGUID "### GUID ###" -clientName "### Client Name ###" Update an client cotacts Set-AppFactoryClient -clientGUID "### GUID ###" -clientContact "### Contact 1 ###","### Contact 2 ###" #> function Set-AppFactoryServiceClient{ [CmdletBinding()] [Alias("Set-AppFactoryOrganization")] param( [Alias("GUID")][Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$clientGUID, [Alias("Name")][Parameter()][ValidateNotNullOrEmpty()][string]$clientName, [Alias("contactList")][Parameter()][string[]]$clientContact, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) # Get Client Configuration Files $client = Get-AppFactoryServiceClient -GUID $clientGUID -LogLevel $LogLevel if ($null -eq $client) { Write-PSFMessage -Message "Error Encountered: Client not found." -Level "Error" -Tag "Client","$($clientGUID)" -Target "Application Factory Service" throw "CLient not found." } # Flag to know if we actually updated anything $changed = $false # If Contact List is Set to Be Updated if($null-ne $clientContact -and $clientContact -ne "" -and $PSBoundParameters.ContainsKey("clientContact")){ if($script:AppFactoryLogging){ Write-PSFMessage -Message "[$($client.Name)] Updating Contact List - <c='green'>$($clientContact -join ",")</c>" -Level $LogLevel -Tag "Clients","ContactList","$($client.Name)","$($clientGUID)" -Target "Application Factory Service" } $client.Contacts = $clientContact $changed = $true } # If the contact list is meant to be cleaned elseif($PSBoundParameters.ContainsKey("clientContact")){ if($script:AppFactoryLogging){ Write-PSFMessage -Message "[$($client.Name)] Clearning contact list." -Level $LogLevel -Tag "Clients","ContactList","$($client.Name)","$($clientGUID)" -Target "Application Factory Service" } $client.Contacts = @() $changed = $true } if($PSBoundParameters.ContainsKey("clientName")){ if($script:AppFactoryLogging){ Write-PSFMessage -Message "[$($client.Name)] Updating Name - <c='green'>$($clientName)</c>" -Level $LogLevel -Tag "Clients","clientName","$($client.Name)","$($clientGUID)" -Target "Application Factory Service" } $client.Name = $clientName $changed = $true } # If something has been changed, lets do some updates if($changed){ # Get Current Path of client File $fileName = Join-Path -Path $script:AppFactorySourceDir -ChildPath "Clients" -AdditionalChildPath $client.FileName # Remove the filename property since we will be writing out the configuration $client.PsObject.properties.Remove("fileName") try{ $client | ConvertTo-Json -Depth 3 | Out-File $fileName if($script:AppFactoryLogging){ Write-PSFMessage -Message "[$($client.Name)] Saved configuration file" -Level $LogLevel -Tag "Clients","$($client.Name)","$($clientGUID)" -Target "Application Factory Service" } # If the client name is to be changed. update the filename to match. if($PSBoundParameters.ContainsKey("clientName")){ Rename-Item -Path $fileName -NewName "$($clientName).json" -Force if($script:AppFactoryLogging){ Write-PSFMessage -Message "[$($client.Name)] Renamed configuration file" -Level $LogLevel -Tag "Clients","$($client.Name)","$($clientGUID)" -Target "Application Factory Service" } } } catch{ Write-PSFMessage -Message "Error Encountered: $($_)" -Level "Error" -Tag "Clients","$($client.Name)","$($clientGUID)" -Target "Application Factory Service" throw $_ } } return $client } #EndRegion '.\Public\Set-AppFactoryServiceClient.ps1' 87 #Region '.\Public\Set-AppFactoryServiceClientAppConfig.ps1' 0 function Set-AppFactoryServiceClientAppConfig{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$orgGUID, [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$appGUID, [Parameter()][bool]$AddToIntune, [Parameter()][string[]]$AvailableAssignments, [Parameter()][string[]]$AvailableExceptions, [Parameter()][string[]]$RequiredAssignments, [Parameter()][string[]]$RequiredExceptions, [Parameter()][string[]]$UninstallAssignments, [Parameter()][string[]]$UninstallExceptions, [Parameter()][bool]$UnassignPrevious, [Parameter()][bool]$CopyPrevious, [Parameter()][int]$KeepPrevious, [Parameter()][bool]$foreground, [Parameter()][PSCustomObject]$filters, [Parameter()][string[]]$espprofiles, [Parameter()][bool]$InteractiveInstall, [Parameter()][bool]$InteractiveUninstall, [Parameter()][String]$AppVersion, [Parameter()][ValidateSet("Output","Verbose")][string]$LogLevel = "Verbose" ) $currentConfig = Get-AppFactoryServiceClientAppConfig -orgGUID $orgGUID -appGUID $appGUID -LogLevel $LogLevel if(-not $currentConfig){$currentConfig = [PSCustomObject]@{}} foreach($item in $PSBoundParameters.GetEnumerator()){ if($item.key -in ("orgGUID","appGUID","LogLevel")){continue} #$itemType = $item.Value.GetType().Name $action = $null if($item.key -in $currentConfig.psobject.properties.Name){ $Action = "Update" switch -regex ($item.Value.GetType().Name){ "Boolean" { if(-not [System.Convert]::ToBoolean($item.Value)){ $action = "Remove" } } "String|String\[\]|PSCustomObject" { if([String]::IsNullOrWhiteSpace($item.value) -or $item.value -eq "0.0"){ $Action = "Remove" } } "Int32" { if($item.value -eq 0){ $Action = "Remove" } } default { $Action = "Unknown" } } } else{ switch -regex ($item.Value.GetType().Name){ "Boolean" { if([System.Convert]::ToBoolean($item.Value)){ $action = "Add" } } "String|String\[\]|PSCustomObject" { if(-not ([String]::IsNullOrWhiteSpace($item.value)) -and $item.value -ne "0.0"){ $Action = "Add" } } "Int32" { if($item.value -ne 0){ $Action = "Add" } } } } switch($Action){ "Add"{ $currentConfig | Add-Member -MemberType NoteProperty -Name $item.Key -Value $item.Value -Force } "Remove"{ $currentConfig.PSObject.Properties.Remove($item.Key) } "Update"{ $currentConfig.$($item.Key) = $item.Value } } } $ClientConfigFolderPath = Join-Path -Path $script:AppFactoryClientConfigDir -ChildPath "$($orgGUID)" $ClientAppConfig = Join-Path -Path $ClientConfigFolderPath -ChildPath "$($appGUID).json" if(-not (Test-Path $ClientConfigFolderPath)){ New-Item -Path $ClientConfigFolderPath -ItemType Directory -Force | Out-Null } $currentConfig | ConvertTo-JSON | Out-File -Path $ClientAppConfig -Force } #EndRegion '.\Public\Set-AppFactoryServiceClientAppConfig.ps1' 92 #Region '.\Public\Start-AppFactoryClient.ps1' 0 function Start-AppFactoryClient { [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$ClientServicePath, [Parameter()][ValidateNotNullOrEmpty()][string]$configuration = "Configuration.json", [Parameter()][string]$LocalModule = $null, [Parameter()][switch]$EnableLogging, [Parameter()][int]$retries = 5, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) # Start the Application Factory Process $init = @{ ClientServicePath = $ClientServicePath EnableLogging = $EnableLogging.IsPresent configuration = $configuration retries = $retries LocalModule = $LocalModule } Initialize-AppFactoryClientProcess @init Write-PSFMessage -Message "Getting list of applications configurations from service." -Level $LogLevel -Tag "Process" -Target "Application Factory Client" # Clean Up Old Configuration Files that may remain Get-ChildItem -Path (Join-Path -Path $script:AppFactoryClientSourceDir -ChildPath "Apps") -filter "*.json" | Remove-Item -Force Get-AppFactoryClientAppList -LogLevel $LogLevel # Clean old credential that is set to global by third party module $PublishedApplications = [System.Collections.Generic.List[PSCustomObject]]@() for($x = 0; $x -lt $retries; $x++){ try{ # Keep track of packaged applications $applicationList = Get-AppFactoryClientApp -AddToIntune $true -LogLevel $LogLevel Write-PSFMessage -Message "There are <c='green'>$($applicationList.count)</c> application set to be configured in intune" -Level $LogLevel -Tag "Process" -Target "Application Factory Client" if($applicationList.count -eq 0){ Write-PSFMessage -Message "No applications found to process" -Level $LogLevel -Tag "Process" -Target "Application Factory Client" return $PublishedApplications } $intuneApplications = Get-AppFactoryClientGraphApp -LogLevel $LogLevel $publish = Compare-AppFactoryClientAppVersions -applicationList $applicationList -intuneapplications $intuneApplications -LogLevel $LogLevel Write-PSFMessage -Message "There are <c='green'>$($publish.count)</c> application set to be configured in intune" -Level $LogLevel -Tag "Process" -Target "Application Factory Client" if($publish.count -eq 0){ return $PublishedApplications } # Make a note of how many applications we are expecting to update $originalCount = $publish.count # Get application SAS tokens Get-AppFactoryClientSAS foreach($application in $publish){ try{ Get-AppFactoryClientAppFiles -applications $application -LogLevel $LogLevel Write-PSFMessage -Message "[<c='green'>$($application.IntuneAppName)</c>] Downloaded files." -Level $LogLevel -Tag "Applications","$($application.IntuneAppName)" -Target "Application Factory Client" $PublishedApp = Publish-AppFactoryClientApp -application $application -LogLevel $LogLevel Write-PSFMessage -Message "[<c='green'>$($application.IntuneAppName)</c>] Pausing to ensure replication." -Level $LogLevel -Tag "Applications","$($application.IntuneAppName)" -Target "Application Factory Client" Start-Sleep -Seconds 30 if($PublishedApp.UploadState -eq 0){ throw "Failed to upload files." } Add-AppFactoryClientAppAssignments -application $application -intuneid $PublishedApp.id -LogLevel $LogLevel Copy-AppFactoryClientAppAssignments -application $application -intuneid $PublishedApp.id -intuneApplications $intuneApplications -LogLevel $LogLevel Remove-AppFactoryClientApp -application $application -intuneApplications $intuneApplications -LogLevel $LogLevel Add-AppFactoryClientESPAssignment -application $application -intuneid $PublishedApp.id -LogLevel $LogLevel Write-PSFMessage -Message "[<c='green'>$($application.IntuneAppName)</c>] Completed." -Level $LogLevel -Tag "Applications","$($application.IntuneAppName)" -Target "Application Factory Client" $PublishedApplications.Add($application) | Out-Null } catch{ if($PublishedApp){ Remove-GraphIntuneApp -applicationid $PublishedApp.id } Remove-AppFactoryClientAppFiles -applications $application -LogLevel $LogLevel Write-PSFMessage -Message "[<c='green'>$($application.IntuneAppName)</c>] Unable to complete process for application, please review the logs to what has failed. Error: $($_)" -Level Error -Tag "Applications","$($application.IntuneAppName)" -Target "Application Factory Client" continue } } if($originalCount -ne $PublishedApplications.Count){ throw } return $PublishedApplications } catch{ Write-PSFMessage -Message "==========================================================================================" -Level "Error" -Tag "Process","IntuneError" -Target "Application Factory Client" Write-PSFMessage -Message "An Error Occured and not all applications where published. We will try again in 5." -Level "Error" -Tag "Process","IntuneError" -Target "Application Factory Client" Write-PSFMessage -Message "==========================================================================================" -Level "Error" -Tag "Process","IntuneError" -Target "Application Factory Client" Start-Sleep -Seconds 300 } } } #EndRegion '.\Public\Start-AppFactoryClient.ps1' 84 #Region '.\Public\Start-AppFactoryProcess.ps1' 0 function Start-AppFactoryProcess{ [CmdletBinding()] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$ApplicationServicePath, [Parameter()][switch]$EnableLogging, [Parameter()][string[]]$AppList, [Parameter()][switch]$force, [Parameter()][switch]$testmode, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) # Start the Application Factory Process Initialize-AppFactoryProcess -ApplicationServicePath $ApplicationServicePath -EnableLogging:$EnableLogging.IsPresent -LogLevel $LogLevel # Get All applications in the process $AllApplications = Get-AppFactoryApp -active # If set to filter to specific application file if ($PSBoundParameters.ContainsKey("AppList")){ $AllApplications = $AllApplications | Where-Object { $_.GUID -in $AppList } } if($EnableLogging.IsPresent){ Write-PSFMessage -Message "There are <c='green'>$($AllApplications.count)</c> applications configured in AppFactory" -Level "Output" -Tag "Process" -Target "Application Factory Service" Write-PSFMessage -Message "Getting the latest version number for each application in the process" -Level "Output" -Tag "Process" -Target "Application Factory Service" } if($AllApplications.Count -eq 0){ Write-PSFMessage -Message "No applications set to active in AppFactory" -Level "Output" -Tag "Process" -Target "Application Factory Service" return } $ApplicationList = Test-AppFactoryAppVersion -applicationList $AllApplications -LogLevel $LogLevel -force:$force.IsPresent if($ApplicationList.Count -eq 0){ Write-PSFMessage -Message "No new versions of applications found" -Level "Output" -Tag "Process" -Target "Application Factory Service" return } if($EnableLogging.IsPresent){ Write-PSFMessage -Message "There are <c='green'>$($applicationList.count)</c> apps that require an update." -Level "Output" -Tag "Process" -Target "Application Factory Service" } $PublishedApplications = [System.Collections.Generic.List[PSCustomObject]]@() foreach($Application in $ApplicationList){ try{ $publish = Test-AppFactoryFiles -applicationList $Application -LogLevel $LogLevel if($publish.Count -eq 0){throw "No applications to process."} $publish = Get-AppFactoryInstaller -applicationList $publish -LogLevel $LogLevel if($publish.Count -eq 0){throw "No applications to process."} $publish = New-AppFactoryPackage -applicationList $publish -LogLevel $LogLevel if($publish.Count -eq 0){throw "No applications to process."} try{ Publish-AppFactoryAppInstall -application $publish -LogLevel $LogLevel } catch{ throw "Updated install lines for application." } try{ Publish-AppFactoryAppUninstall -application $publish -LogLevel $LogLevel } catch{ throw "Updated uninstall lines for application." } $publish = New-AppFactoryIntuneFile -applicationList $publish -LogLevel $LogLevel if($publish.Count -eq 0){throw "No applications to process."} if(-not $testmode.IsPresent){ $publish = Publish-AppFactoryIntunePackage -applicationList $publish -LogLevel $LogLevel if($publish.Count -gt 0){ foreach($app in $publish){ Write-PSFMessage -Message "[<c='green'>$($app.Information.DisplayName)</c>] Application published." -Level "Output" -Tag "Process",$app.Information.DisplayName -Target "Application Factory Service" } } else{throw "No applications to process."} Remove-AppFactoryProcessFiles -applicationList $publish -LogLevel $LogLevel } else{ if($EnableLogging.IsPresent){ Write-PSFMessage -Message "[<c='green'>$($application.Information.DisplayName)</c>] <c='yellow'>running in test mode so did not publish or remove files.</c>" -Level "Output" -Tag "Process",$application.Information.DisplayName -Target "Application Factory Service" } } $PublishedApplications.Add($Application) } catch{ Write-PSFMessage -Message "[<c='green'>$($application.Information.DisplayName)</c>] Application failed to upload with error: $($_)." -Level "Error" -Tag "Process",$application.Information.DisplayName,"IntuneError" -Target "Application Factory Service" } } } #EndRegion '.\Public\Start-AppFactoryProcess.ps1' 82 #Region '.\Public\Test-AppFactoryAppVersion.ps1' 0 function Test-AppFactoryAppVersion{ [CmdletBinding()] [OutputType([System.Collections.Hashtable])] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][System.Collections.Generic.List[PSCustomObject]]$applicationList, [Parameter()][ValidateNotNullOrEmpty()][switch]$force, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) $FilteredList = [System.Collections.Generic.List[PSCustomObject]]::new() foreach($Application in $ApplicationList){ if($application.SourceFiles.PauseUpdate){ if ($script:AppFactoryLogging) { Write-PSFMessage -Message "[<c='green'>$($application.Information.DisplayName)</c>] <c='yellow'>Updates are paused for this application.</c>" -Level $LogLevel -Tag "Application", "$($application.Information.DisplayName)" -Target "AppFactory" } continue } switch ($Application.SourceFiles.AppSource) { "ECNO" {$AppItem = Get-AppFactoryECNOAppItem -application $Application -LogLevel $LogLevel} "Sharepoint" {$AppItem = Get-AppFactorySharepointAppItem -application $Application -LogLevel $LogLevel} "LocalStorage" {$AppItem = Get-AppFactoryLocalStorageAppItem -application $Application -LogLevel $LogLevel} "StorageAccount" {$AppItem = Get-AppFactoryAzureStorageAppItem -application $Application -LogLevel $LogLevel} "Winget" { $AppItem = Get-AppFactoryWinGetAppItem -application $Application -LogLevel $LogLevel } "Evergreen" {$AppItem = Get-AppFactoryEvergreenAppItem -application $Application -LogLevel $LogLevel} "PSADT" { $AppItem = Get-AppFactoryPSADTAppItem -application $application -LogLevel $LogLevel } } if($null -ne $AppItem){ $required = $false if($application.SourceFiles.publishTo.count -eq 0){ if($script:PublishedAppList.Public.Name -notcontains "$($application.GUID)/$($AppItem.Version)/App.json"){ if ($script:AppFactoryLogging) { Write-PSFMessage -Message "[<c='green'>$($application.Information.DisplayName)</c>] Specified version (<c='green'>$($AppItem.Version)</c>) is not already packaged in the public container." -Level $LogLevel -Tag "Application", "$($application.Information.DisplayName)" -Target "AppFactory" } $required = $true } } else{ foreach($publishTo in $application.SourceFiles.publishTo){ if($script:PublishedAppList.$($publishTo).Name -notcontains "$($application.GUID)/$($AppItem.Version)/App.json"){ Write-PSFMessage -Message "[<c='green'>$($application.Information.DisplayName)</c>] Specified version (<c='green'>$($AppItem.Version)</c>) is not already packaged in the <c='green'>$($publishTo)</c> container." -Level $LogLevel -Tag "Application", "$($application.Information.DisplayName)" -Target "AppFactory" $required = $true } } } if($required -or $force.IsPresent){ if ($script:AppFactoryLogging) { if($force.IsPresent){ Write-PSFMessage -Message "[<c='green'>$($application.Information.DisplayName)</c>] Currently the specified version (<c='green'>$($AppItem.Version)</c>) of the application is already packaged but force is set." -Level $LogLevel -Tag "Application", "$($application.Information.DisplayName)", "WinGet" -Target "AppFactory" } else{ Write-PSFMessage -Message "[<c='green'>$($application.Information.DisplayName)</c>] Specified version (<c='green'>$($AppItem.Version)</c>) is not already packaged in at least one of the expected clients." -Level $LogLevel -Tag "Application", "$($application.Information.DisplayName)", "WinGet" -Target "AppFactory" } } $Application.Information.AppVersion = $AppItem.Version if(($application.DetectionRule | Get-Member -Name Value)){ $application.DetectionRule[0].Value = $AppItem.Version } $Application.SourceFiles | Add-Member -MemberType NoteProperty -Name "PackageVersion" -Value $AppItem.Version -Force $Application.SourceFiles | Add-Member -MemberType NoteProperty -Name "PackageSource" -Value $AppItem.URI -Force $FilteredList.Add($Application) } else{ if ($script:AppFactoryLogging) { Write-PSFMessage -Message "[<c='green'>$($application.Information.DisplayName)</c>] Currently the version specfieid (<c='green'>$($AppItem.Version)</c>) of the application is already packaged and force is not set." -Level $LogLevel -Tag "Application", "$($application.Information.DisplayName)", "WinGet" -Target "AppFactory" } } } } return $FilteredList } #EndRegion '.\Public\Test-AppFactoryAppVersion.ps1' 70 #Region '.\Public\Test-AppFactoryFiles.ps1' 0 function Test-AppFactoryFiles { [CmdletBinding()] [OutputType([System.Collections.Generic.List[PSCustomObject]])] param( [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][PSCustomObject]$applicationList, [Parameter()][ValidateSet("Output", "Verbose")][string]$LogLevel = "Verbose" ) # Create blank list to store the applications that we will be moving forward with. $applications = [System.Collections.Generic.List[PSCustomObject]]@() # What files should exist $AppFileNames = @("Install.ps1","unInstall.ps1","detection.ps1", "Icon.png","ApplicationConfig.json") # Loop through each of the applications foreach ($application in $applicationList) { $AppPackageFolderPath = Join-Path -Path $script:AppFactorySourceDir -ChildPath "Apps" -AdditionalChildPath $application.Information.AppFolderName # Check for the required files try{ foreach ($AppFileName in $AppFileNames) { $filepath = Join-Path -Path $AppPackageFolderPath -ChildPath $AppFileName switch($AppFileName){ {$_ -eq "icon.png"} { if (-not(Test-Path -Path $filepath)) { throw "[$($application.Information.DisplayName)] File Not Found $($filepath). Skipping Application." } } "detection.ps1" { if (-not(Test-Path -Path $filepath) -and $application.DetectionRule.Type -eq "Script") { throw "[$($application.Information.DisplayName)] File Not Found $($filepath). Skipping Application." } } "ApplicationConfig.json" { if ($application.DetectionRule.Count -eq 0) { throw "[$($application.Information.DisplayName)] Could not find any detection rule defined, ensure ApplicationConfig.json contains atleast one detection rule element. Skipping Application." } if ($application.DetectionRule.Count -ge 2) { if ($application.DetectionRule.Type -like "Script") { throw "[$($application.Information.DisplayName)] Multiple detection rule types are defined, where at least one of them are of type 'Script', which is not a supported configuration in Intune. Skipping Application." } } $content = Get-Content -Path $filepath if($content -match "^.*`"###.*###`".*$"){ throw "[$($application.Information.DisplayName)] Not all fields that need to configure inApplicationConfig.json have been updated. Skipping Application." } } } } } catch{ if ($script:AppFactoryLogging) { Write-PSFMessage -Message $_ -Level "Error" -Tag "Application", "$($application.Information.DisplayName)", "Error" -Target "Application Factory Service" } continue } $applications.Add($application) if($script:AppFactoryLogging){ Write-PSFMessage -Message "[<c='green'>$($application.Information.DisplayName)</c>] All files and configurations appear to be correct for application." -Level $LogLevel -Tag "Process","Files" -Target "Application Factory Service" } } return $applications } #EndRegion '.\Public\Test-AppFactoryFiles.ps1' 60 #Region '.\Public\Update-AppFactoryServiceAppConfig.ps1' 0 function Update-AppFactoryServiceAppConfig{ [cmdletbinding()] param() $ApplicationsPath = Join-Path -Path $script:AppFactorySourceDir -ChildPath "Apps" $TemplatePath = Join-Path -Path $script:AppFactorySupportTemplateFolder -ChildPath "Application" -AdditionalChildPath "ApplicationConfig.json" $AllApps = Get-ChildItem -Path $ApplicationsPath -Filter "ApplicationConfig.json" -Recurse $TemplateSections = @("Information","SourceFiles","Install","Uninstall") $Template = Get-Content -Path $TemplatePath -Raw | ConvertFrom-JSON -Depth 10 foreach($app in $AllApps){ $AppDetails = Get-Content -path $app.FullName -Raw | ConvertFrom-JSON -Depth 10 foreach($obj in $TemplateSections){ $properties = $Template.$obj | Get-Member -MemberType NoteProperty | Select-Object -ExpandProperty Name foreach($property in $properties){ if(-not ($AppDetails.$obj.PSObject.Properties.Name -contains $property)){ $AppDetails.$obj | Add-Member -MemberType NoteProperty -Name $property -Value $Template.$obj.$property } } } $AppDetails | ConvertTo-JSON -depth 10 | Out-File -FilePath $app.FullName -Force } } #EndRegion '.\Public\Update-AppFactoryServiceAppConfig.ps1' 22 |