byteben / MEM

40 stars 8 forks source link

Reset-Appx.ps1 - Winget Company Portal install weird behavior, only showing for user after second run if $removeAppxPackage is null #5

Closed Sn00zEZA closed 1 year ago

Sn00zEZA commented 1 year ago

Picking up strange behavior when $removeAppxPackage is passed. Script will remove Company Portal using functions Remove-AppxPkg and Remove-AppxProvPkg, then successfully install Company Portal via winget, but its not detected by "Get-AppXPackage -AllUsers" in the Install-WinGetApp function. Running the script a second time it is detected successfully and the user will have Company Portal available.

Changing "$winGetTest = .\winget.exe list --id $winGetApp --source $winGetAppSource --accept-source-agreements" to include "--scope machine" shows that the app is indeed present. during both script runs.

Just not sure why it only works if $removeAppxPackage is null.

byteben commented 1 year ago

Thanks for flagging as an issue, I saw this last night too. WinGet certainly does weird stuff as SYSTEM.

Sn00zEZA commented 1 year ago

Made an update to the Install-WinGetApp function to rerun the winget install if it was not detected by "$testWinGetInstall = Get-AppXPackage -AllUsers | Where-Object { $_.Name -like $removeApp }". Not sure if this is best way, but it does work.

        if ($winGetAppInstallAttempted) {
            $testWinGetInstall = Get-AppXPackage -AllUsers | Where-Object { $_.Name -like $removeApp } -ErrorAction Stop

            #if (($testWinGetInstall.Name -eq $removeApp) -and ($testWinGetInstall.PackageUserInformation.UserSecurityId.Username -ne "NT AUTHORITY\SYSTEM")) {
            if (($testWinGetInstall.Name -eq $removeApp) -and ($testWinGetInstall.PackageUserInformation.UserSecurityId.Sid -ne "S-1-5-18")) {

                Write-Host "Success: The '$($winGetAppName)' app, with Id $($winGetApp), installed succesfully. Check the Winget logs at 'C:\Windows\Temp\WinGet\defaultState' for more information"
                Write-LogEntry -logEntry "Success: The '$($winGetAppName)' app, with Id '$($winGetApp)', installed succesfully. Check the Winget logs at 'C:\Windows\Temp\WinGet\defaultState' for more information" -logID $logID
            }
            else {
                Write-Warning -Message "Error: The '$($winGetAppName)' app, with Id '$($winGetApp)', did not install succesfully. Check the Winget logs at 'C:\Windows\Temp\WinGet\defaultState' for more information"
                Write-LogEntry -logEntry "Error: The '$($winGetAppName)' app, with Id '$($winGetApp)', did not install succesfully. Check the Winget logs at 'C:\Windows\Temp\WinGet\defaultState' for more information" -logID $logID -severity 3

                # Attempt to re-run installer if AppXPackage was not detected in the previous install
                Write-Host "Re-running install '$($winGetAppName)', with Id '$($winGetApp)', was not detected after previous attempt"
                Write-LogEntry -logEntry "Rerunning install '$($winGetAppName)', with Id '$($winGetApp)', was not detected after previous attempt" -logID $logID
                Write-Host ".\winget.exe install --id '$winGetApp' --accept-package-agreements --accept-source-agreements --source $winGetAppSource --scope machine"
                Write-LogEntry -logEntry ".\winget.exe install --Id '$winGetApp' --accept-package-agreements --accept-source-agreements --source $winGetAppSource --scope machine" -logID $logID

                .\winget.exe install --id $winGetApp --accept-package-agreements --accept-source-agreements --source $winGetAppSource --scope machine

                $testWinGetInstall = Get-AppXPackage -AllUsers | Where-Object { $_.Name -like $removeApp } -ErrorAction Stop
                if ($testWinGetInstall.Name -eq $removeApp) {

                    Write-Host "Success: The '$($winGetAppName)' app, with Id $($winGetApp), installed succesfully. Check the Winget logs at 'C:\Windows\Temp\WinGet\defaultState' for more information"
                    Write-LogEntry -logEntry "Success: The '$($winGetAppName)' app, with Id '$($winGetApp)', installed succesfully. Check the Winget logs at 'C:\Windows\Temp\WinGet\defaultState' for more information" -logID $logID
                }
                else {
                    Write-Warning -Message "Error: The '$($winGetAppName)' app, with Id '$($winGetApp)', did not install succesfully. Check the Winget logs at 'C:\Windows\Temp\WinGet\defaultState' for more information"
                    Write-LogEntry -logEntry "Error: The '$($winGetAppName)' app, with Id '$($winGetApp)', did not install succesfully. Check the Winget logs at 'C:\Windows\Temp\WinGet\defaultState' for more information" -logID $logID -severity 3
                }
            }
        }
theITcloudAdmn commented 1 year ago

Thanks @Sn00zEZA Had the same problem, your code modification solved it for me too.

Update: As I'm further testing the modified script I've found out, that it only works if it runs twice. Not sure yet why...

theITcloudAdmn commented 1 year ago

Probably found out why @Sn00zEZA code update didn't solve the problem for me: ($testWinGetInstall.PackageUserInformation.UserSecurityId.Username -ne "NT AUTHORITY\SYSTEM") I'm working on german Windows. In german OS it's "NT-AUTORITÄT\SYSTEM" (thanks Microsoft!)...

I think this is the better solution, the SID stays the same no matter the OS localization: ($testWinGetInstall.PackageUserInformation.UserSecurityId.Sid -ne "S-1-5-18")

Sn00zEZA commented 1 year ago

Ah that would make sense. Will update my script with this also. Thank you for raising this.

byteben commented 1 year ago

Thanks @theITcloudAdmn and @Sn00zEZA This makes sense. I am also unsure why it needs running twice on some systems.

I will proceed with the code mod later today. Appreciate your input here! Ben

Guardempire commented 1 year ago

I have tried the script in our environment and it works fine for those who have the old installation on the machine. If you set up a new device, which by default gets the new Company Portal via Winget, the script unfortunately uninstalls the portal directly again. If you run the script again, it is installed again, the next time then removed again. The change of Sn00zEZA does not solve the problem for me. Then, according to the log, it recognizes an existing version that it wants to update, finds no update, claims it was successful, but the portal is not present.

I run the script via Live Response Session, it should behave similar to Intune?

byteben commented 1 year ago

Can you please try version 1.06.27.0 winget was installing the appxprovisionedpackage but the manifest was not registering which would result in the app not appearing for the logged on user. New users logging on should have the appx package provisioned ok

Guardempire commented 1 year ago

Different behavior, same result. If it is started once and it is already present, it is not executable afterwards. If you start the script again, it works and then always in alternation. It is interesting that the script throws an error if it works afterwards. If there is no error at the end, the Company Portal does not work. I copy the message here, but unfortunately it is in German.

I start the script via the live response session on the notebook.

Errors: Add-AppxPackage : Fehler bei Bereitstellung. HRESULT: 0x80073CF9, Fehler bei der Installation. Wenden Sie sich an den Softwarehersteller. (Ausnahme von HRESULT: 0x80073CF9) Der Bereitstellungsvorgang Register für das Paket "Microsoft.CompanyPortal_11.2.119.0neutral~8wekyb3d8bbwe" von der Installationsanforderung "AppxBundleManifest.xml" wurde abgelehnt, da dieser Vorgang mit dem lokalen Systemkonto nicht ausgeführt werden darf. HINWEIS: Wenn Sie weitere Informationen wünschen, suchen Sie im Ereignisprotokoll nach [ActivityId] b9c38e26-a8e1-0001-d9a6-cfb9e1a8d901, oder verwenden Sie die Befehlszeile Get-AppxLog -ActivityID b9c38e26-a8e1-0001-d9a6-cfb9e1a8d901 In C:\ProgramData\Microsoft\Windows Defender Advanced Threat Protection\Downloads\PSScript{AC5BA350-DDF4-4F1B-B2DB-D1E33A23F074}.ps1:455 Zeichen:112

theITcloudAdmn commented 1 year ago

Would be super interesting to understand, why sometimes the app gets installed just for the system user in this strange state (check PackageUserInformation)!

So I ended up with this (not really nice but does the job):

  1. Adjusted the modification from @Sn00zEZA sligthly so if the app isn't installed correctly after 2nd try, script will end with exit code 1. Like that, Intune will do another rerun of the script which normaly ends with success. And I'm checking after both installation attempts if the app is there and not installed for System (SID "S-1-5-18").
        if ($winGetAppInstallAttempted) {
            $testWinGetInstall = Get-AppXPackage -AllUsers | Where-Object { $_.Name -like $removeApp } -ErrorAction Stop

            if (($testWinGetInstall.Name -eq $removeApp) -and ($testWinGetInstall.PackageUserInformation.UserSecurityId.Sid -ne "S-1-5-18")) {

                Write-Host "Success: The '$($winGetAppName)' app, with Id $($winGetApp), installed succesfully. Check the Winget logs at 'C:\Windows\Temp\WinGet\defaultState' for more information"
                Write-LogEntry -logEntry "Success: The '$($winGetAppName)' app, with Id '$($winGetApp)', installed succesfully. Check the Winget logs at 'C:\Windows\Temp\WinGet\defaultState' for more information" -logID $logID
            }
            else {
                Write-Warning -Message "Error: The '$($winGetAppName)' app, with Id '$($winGetApp)', did not install succesfully. Check the Winget logs at 'C:\Windows\Temp\WinGet\defaultState' for more information"
                Write-LogEntry -logEntry "Error: The '$($winGetAppName)' app, with Id '$($winGetApp)', did not install succesfully. Check the Winget logs at 'C:\Windows\Temp\WinGet\defaultState' for more information" -logID $logID -severity 3

                # Attempt to re-run installer if AppXPackage was not detected in the previous install
                Write-Host "Re-running install '$($winGetAppName)', with Id '$($winGetApp)', was not detected after previous attempt"
                Write-LogEntry -logEntry "Rerunning install '$($winGetAppName)', with Id '$($winGetApp)', was not detected after previous attempt" -logID $logID
                Write-Host ".\winget.exe install --id '$winGetApp' --accept-package-agreements --accept-source-agreements --source $winGetAppSource --scope machine"
                Write-LogEntry -logEntry ".\winget.exe install --Id '$winGetApp' --accept-package-agreements --accept-source-agreements --source $winGetAppSource --scope machine" -logID $logID

                .\winget.exe install --id $winGetApp --accept-package-agreements --accept-source-agreements --source $winGetAppSource --scope machine

                $testWinGetInstall = Get-AppXPackage -AllUsers | Where-Object { $_.Name -like $removeApp } -ErrorAction Stop
                if (($testWinGetInstall.Name -eq $removeApp) -and ($testWinGetInstall.PackageUserInformation.UserSecurityId.Sid -ne "S-1-5-18")) {

                    Write-Host "Success: The '$($winGetAppName)' app, with Id $($winGetApp), installed succesfully. Check the Winget logs at 'C:\Windows\Temp\WinGet\defaultState' for more information"
                    Write-LogEntry -logEntry "Success: The '$($winGetAppName)' app, with Id '$($winGetApp)', installed succesfully. Check the Winget logs at 'C:\Windows\Temp\WinGet\defaultState' for more information" -logID $logID
                }
                else {
                    Write-Warning -Message "Error: The '$($winGetAppName)' app, with Id '$($winGetApp)', did not install succesfully. Check the Winget logs at 'C:\Windows\Temp\WinGet\defaultState' for more information"
                    Write-LogEntry -logEntry "Error: The '$($winGetAppName)' app, with Id '$($winGetApp)', did not install succesfully. Check the Winget logs at 'C:\Windows\Temp\WinGet\defaultState' for more information" -logID $logID -severity 3
                    Write-Output -Message "Stopped processing the script with error code 1"
                    Write-LogEntry -logEntry "Stopped processing the script with error code 1" -logID $logID
                    Set-Location $PSScriptRoot
                    Exit 1
                }
            }
        }
  1. Built a remediation script as addition to detect if the app is correctly installed (as remediation the Reset-Appx.ps1 script is run):
$CheckApp = "Microsoft.CompanyPortal"

Try {
    $TestAppxInstall = Get-AppXPackage -AllUsers | Where-Object { $_.Name -like $CheckApp } -ErrorAction Stop
    If (($TestAppxInstall.Name -eq $CheckApp) -and ($TestAppxInstall.PackageUserInformation.UserSecurityId.Sid -ne "S-1-5-18")){
        Write-Output $TestAppxInstall
        Write-Output "Compliant - Found App '$($CheckApp)'"
        Exit 0
    } 
    Write-Output $TestAppxInstall
    Write-Warning "Not Compliant - App '$($CheckApp)' not found!"
    Exit 1
} 
Catch {
    Write-Output $TestAppxInstall
    Write-Warning "Not Compliant - Error processing Script!"
    Exit 1
}

Testing looks promising. Think I'm going to roll this out to production.

byteben commented 1 year ago

Thanks for the info. I am looking at a regression issue in the new version. I like the idea of exiting with code 1, that makes sense and will retry when delivered as an Intune script (max 3 times)

Why it requires a 2nd retry sometimes still remains a mystery to me

Ben Whitmore Enterprise Mobility MVP


From: theITcloudAdmn @.> Sent: Wednesday, June 28, 2023 8:03:08 AM To: byteben/MEM @.> Cc: Ben Whitmore @.>; Comment @.> Subject: Re: [byteben/MEM] Reset-Appx.ps1 - Winget Company Portal install weird behavior, only showing for user after second run if $removeAppxPackage is null (Issue #5)

Would be super interesting to understand, why sometimes the app gets installed just for the system user in this strange state (check PackageUserInformation)!

So I ended up with this (not really nice but does the job):

  1. Adjusted the modification from @Sn00zEZAhttps://github.com/Sn00zEZA sligthly so if the app isn't installed correctly after 2nd try, script will end with exit code 1. Like that, Intune will do another rerun of the script which normaly ends with success.

    if ($winGetAppInstallAttempted) {
        $testWinGetInstall = Get-AppXPackage -AllUsers | Where-Object { $_.Name -like $removeApp } -ErrorAction Stop
    
        if (($testWinGetInstall.Name -eq $removeApp) -and ($testWinGetInstall.PackageUserInformation.UserSecurityId.Sid -ne "S-1-5-18")) {
    
            Write-Host "Success: The '$($winGetAppName)' app, with Id $($winGetApp), installed succesfully. Check the Winget logs at 'C:\Windows\Temp\WinGet\defaultState' for more information"
            Write-LogEntry -logEntry "Success: The '$($winGetAppName)' app, with Id '$($winGetApp)', installed succesfully. Check the Winget logs at 'C:\Windows\Temp\WinGet\defaultState' for more information" -logID $logID
        }
        else {
            Write-Warning -Message "Error: The '$($winGetAppName)' app, with Id '$($winGetApp)', did not install succesfully. Check the Winget logs at 'C:\Windows\Temp\WinGet\defaultState' for more information"
            Write-LogEntry -logEntry "Error: The '$($winGetAppName)' app, with Id '$($winGetApp)', did not install succesfully. Check the Winget logs at 'C:\Windows\Temp\WinGet\defaultState' for more information" -logID $logID -severity 3
    
            # Attempt to re-run installer if AppXPackage was not detected in the previous install
            Write-Host "Re-running install '$($winGetAppName)', with Id '$($winGetApp)', was not detected after previous attempt"
            Write-LogEntry -logEntry "Rerunning install '$($winGetAppName)', with Id '$($winGetApp)', was not detected after previous attempt" -logID $logID
            Write-Host ".\winget.exe install --id '$winGetApp' --accept-package-agreements --accept-source-agreements --source $winGetAppSource --scope machine"
            Write-LogEntry -logEntry ".\winget.exe install --Id '$winGetApp' --accept-package-agreements --accept-source-agreements --source $winGetAppSource --scope machine" -logID $logID
    
            .\winget.exe install --id $winGetApp --accept-package-agreements --accept-source-agreements --source $winGetAppSource --scope machine
    
            $testWinGetInstall = Get-AppXPackage -AllUsers | Where-Object { $_.Name -like $removeApp } -ErrorAction Stop
            if ($testWinGetInstall.Name -eq $removeApp) {
    
                Write-Host "Success: The '$($winGetAppName)' app, with Id $($winGetApp), installed succesfully. Check the Winget logs at 'C:\Windows\Temp\WinGet\defaultState' for more information"
                Write-LogEntry -logEntry "Success: The '$($winGetAppName)' app, with Id '$($winGetApp)', installed succesfully. Check the Winget logs at 'C:\Windows\Temp\WinGet\defaultState' for more information" -logID $logID
            }
            else {
                Write-Warning -Message "Error: The '$($winGetAppName)' app, with Id '$($winGetApp)', did not install succesfully. Check the Winget logs at 'C:\Windows\Temp\WinGet\defaultState' for more information"
                Write-LogEntry -logEntry "Error: The '$($winGetAppName)' app, with Id '$($winGetApp)', did not install succesfully. Check the Winget logs at 'C:\Windows\Temp\WinGet\defaultState' for more information" -logID $logID -severity 3
                Write-Output -Message "Stopped processing the script with error code 1"
                Write-LogEntry -logEntry "Stopped processing the script with error code 1" -logID $logID
                Set-Location $PSScriptRoot
                Exit 1
            }
        }
    }
  2. Built a remediation script as addition to detect if the app is correctly installed (as remediation the Reset-Appx.ps1 script is run):

$CheckApp = "Microsoft.CompanyPortal"

Try { $TestAppxInstall = Get-AppXPackage -AllUsers | Where-Object { $_.Name -like $CheckApp } -ErrorAction Stop If (($TestAppxInstall.Name -eq $CheckApp) -and ($TestAppxInstall.PackageUserInformation.UserSecurityId.Sid -ne "S-1-5-18")){ Write-Output $TestAppxInstall Write-Output "Compliant - Found App '$($CheckApp)'" Exit 0 } Write-Output $TestAppxInstall Write-Warning "Not Compliant - App '$($CheckApp)' not found!" Exit 1 } Catch { Write-Output $TestAppxInstall Write-Warning "Not Compliant - Error processing Script!" Exit 1 }

Testing looks promising. Think I'm going to roll this out to production.

— Reply to this email directly, view it on GitHubhttps://github.com/byteben/MEM/issues/5#issuecomment-1610880005, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AKSAHIEB5BVNI6MO3MIGLYLXNPJKZANCNFSM6AAAAAAZNCDB4M. You are receiving this because you commented.Message ID: @.***>

byteben commented 1 year ago

Found the root cause of this. There are 2 possible error conditions after using winget to install the app as system. We can triage both now we understand the issue. Fix coming in v2 of script

byteben commented 1 year ago

All 3 conditions listed below are fixed in V1.07.03.0 of Reset-Appx.ps1 Bug Fixes, Enhancements and Refactoring 🪲🌟🧑‍💻

Condition 1: When WinGet installs the app as SYSTEM, the AppxPackage can fail to register so the AppxPackage regresses, resulting in the ap not being available for the user.

Condition 2: The AppxPackage was staged as SYSTEM

Condition 3: After the WinGet install, WinGet list did not detect the app

WinGet will retry 10 times (by default) to install the app successfully and ensure the conditions above are not present. There is also a 30 second wait (by default) when testing the AppxPackage after WinGet has installed the app

ngjrjeff commented 3 months ago

Sorry. I used the latest version of the script and i still have to run the second time before company portal app is visible to the user computer