Apps installation library

The content provides a comprehensive library for installing and uninstalling various applications, including scripts and policies for Notion, Google Drive, Microsoft Teams, and Microsoft Office 365, along with details on ownership, status, and visibility.

7 min read

Windows

Notion

Policy

SELECT name FROM programs WHERE name LIKE 'Notion%'

Install script

# Some installers require a flag to run silently.
# Each installer might use a different argument (usually it's "/S" or "/s")
$installArgs = "/S"

$exeFilePath = "${env:INSTALLER_PATH}"

$exitCode = 0

try {

# Copy the installer to a public folder so that all can access it
# users
$exeFilename = Split-Path $exeFilePath -leaf
Copy-Item -Path $exeFilePath -Destination "${env:PUBLIC}" -Force
$exeFilePath = "${env:PUBLIC}\$exeFilename"

# Task properties. The task will be started by the logged in user
$action = New-ScheduledTaskAction -Execute "$exeFilePath" `
    -Argument "$installArgs"
$trigger = New-ScheduledTaskTrigger -AtLogOn
$userName = Get-CimInstance -ClassName Win32_ComputerSystem |
        Select-Object -expand UserName
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries

# Create a task object with the properties defined above
$task = New-ScheduledTask -Action $action -Trigger $trigger `
    -Settings $settings

# Register the task
$taskName = "fleet-install-$exeFilename"
Register-ScheduledTask "$taskName" -InputObject $task -User "$userName"

# keep track of the start time to cancel if taking too long to start
$startDate = Get-Date

# Start the task now that it is ready
Start-ScheduledTask -TaskName "$taskName" -TaskPath "\"

# Wait for the task to be running
$state = (Get-ScheduledTask -TaskName "$taskName").State
Write-Host "ScheduledTask is '$state'"

while ($state  -ne "Running") {
    Write-Host "ScheduledTask is '$state'. Waiting to run .exe..."

    $endDate = Get-Date
    $elapsedTime = New-Timespan -Start $startDate -End $endDate
    if ($elapsedTime.TotalSeconds -gt 120) {
        Throw "Timed-out waiting for scheduled task state."
    }

    Start-Sleep -Seconds 1
    $state = (Get-ScheduledTask -TaskName "$taskName").State
}

# Wait for the task to be done
$state = (Get-ScheduledTask -TaskName "$taskName").State
while ($state  -eq "Running") {
    Write-Host "ScheduledTask is '$state'. Waiting for .exe to complete..."

    $endDate = Get-Date
    $elapsedTime = New-Timespan -Start $startDate -End $endDate
    if ($elapsedTime.TotalSeconds -gt 120) {
        Throw "Timed-out waiting for scheduled task state."
    }

    Start-Sleep -Seconds 10
    $state = (Get-ScheduledTask -TaskName "$taskName").State
}

# Remove task
Write-Host "Removing ScheduledTask: $taskName."
Unregister-ScheduledTask -TaskName "$taskName" -Confirm:$false

} catch {
    Write-Host "Error: $_"
    $exitCode = 1
} finally {
    # Remove installer
    Remove-Item -Path $exeFilePath -Force
}

Exit $exitCode

Uninstall script

# Fleet extracts the name from the installer (EXE) and saves it to PACKAGE_ID
# variable
$softwareName = "Notion"

# Script to uninstall software as the current logged-in user.
$userScript = @'
$softwareName = "Notion"

# Using the exact software name here is recommended to avoid
# uninstalling unintended software.
$softwareNameLike = "*$softwareName*"

# Some uninstallers require additional flags to run silently.
# Each uninstaller might use a different argument (usually it's "/S" or "/s")
$uninstallArgs = "/S"

$uninstallCommand = ""
$exitCode = 0

try {

$userKey = `
 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*'
[array]$uninstallKeys = Get-ChildItem `
    -Path @($userKey) `
    -ErrorAction SilentlyContinue |
        ForEach-Object { Get-ItemProperty $_.PSPath }

$foundUninstaller = $false
foreach ($key in $uninstallKeys) {
    # If needed, add -notlike to the comparison to exclude certain similar
    # software
    if ($key.DisplayName -like $softwareNameLike) {
        $foundUninstaller = $true
        # Get the uninstall command. Some uninstallers do not include
        # 'QuietUninstallString' and require a flag to run silently.
        $uninstallCommand = if ($key.QuietUninstallString) {
            $key.QuietUninstallString
        } else {
            $key.UninstallString
        }

        # The uninstall command may contain command and args, like:
        # "C:\Program Files\Software\uninstall.exe" --uninstall --silent
        # Split the command and args
        $splitArgs = $uninstallCommand.Split('"')
        if ($splitArgs.Length -gt 1) {
            if ($splitArgs.Length -eq 3) {
                $uninstallArgs = "$( $splitArgs[2] ) $uninstallArgs".Trim()
            } elseif ($splitArgs.Length -gt 3) {
                Throw `
                    "Uninstall command contains multiple quoted strings. " +
                        "Please update the uninstall script.`n" +
                        "Uninstall command: $uninstallCommand"
            }
            $uninstallCommand = $splitArgs[1]
        }
        Write-Host "Uninstall command: $uninstallCommand"
        Write-Host "Uninstall args: $uninstallArgs"

        $processOptions = @{
            FilePath = $uninstallCommand
            PassThru = $true
            Wait = $true
        }
        if ($uninstallArgs -ne '') {
            $processOptions.ArgumentList = "$uninstallArgs"
        }

        # Start the process and track the exit code
        $process = Start-Process @processOptions
        $exitCode = $process.ExitCode

        # Prints the exit code
        Write-Host "Uninstall exit code: $exitCode"
        # Exit the loop once the software is found and uninstalled.
        break
    }
}

if (-not $foundUninstaller) {
    Write-Host "Uninstaller for '$softwareName' not found."
    $exitCode = 1
}

} catch {
    Write-Host "Error: $_"
    $exitCode = 1
}

Exit $exitCode
'@

$exitCode = 0

# Create a script in a public folder so that it can be accessed by all users.
$uninstallScriptPath = "${env:PUBLIC}/uninstall-$softwareName.ps1"
$taskName = "fleet-uninstall-$softwareName"
try {
    Set-Content -Path $uninstallScriptPath -Value $userScript -Force

    # Task properties. The task will be started by the logged in user
    $action = New-ScheduledTaskAction -Execute "PowerShell.exe" `
        -Argument "$uninstallScriptPath"
    $trigger = New-ScheduledTaskTrigger -AtLogOn
    $userName = Get-CimInstance -ClassName Win32_ComputerSystem |
            Select-Object -expand UserName
    $settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries

    # Create a task object with the properties defined above
    $task = New-ScheduledTask -Action $action -Trigger $trigger `
        -Settings $settings

    # Register the task
    Register-ScheduledTask "$taskName" -InputObject $task -User "$userName"

    # keep track of the start time to cancel if taking too long to start
    $startDate = Get-Date

    # Start the task now that it is ready
    Start-ScheduledTask -TaskName "$taskName" -TaskPath "\"

    # Wait for the task to be running
    $state = (Get-ScheduledTask -TaskName "$taskName").State
    Write-Host "ScheduledTask is '$state'"

    while ($state  -ne "Running") {
        Write-Host "ScheduledTask is '$state'. Waiting to uninstall..."

        $endDate = Get-Date
        $elapsedTime = New-Timespan -Start $startDate -End $endDate
        if ($elapsedTime.TotalSeconds -gt 120) {
            Throw "Timed-out waiting for scheduled task state."
        }

        Start-Sleep -Seconds 1
        $state = (Get-ScheduledTask -TaskName "$taskName").State
    }

    # Wait for the task to be done
    $state = (Get-ScheduledTask -TaskName "$taskName").State
    while ($state  -eq "Running") {
        Write-Host "ScheduledTask is '$state'. Waiting for .exe to complete..."

        $endDate = Get-Date
        $elapsedTime = New-Timespan -Start $startDate -End $endDate
        if ($elapsedTime.TotalSeconds -gt 120) {
            Throw "Timed-out waiting for scheduled task state."
        }

        Start-Sleep -Seconds 10
        $state = (Get-ScheduledTask -TaskName "$taskName").State
    }

} catch {
    Write-Host "Error: $_"
    $exitCode = 1
} finally {
    # Remove task
    Write-Host "Removing ScheduledTask: $taskName."
    Unregister-ScheduledTask -TaskName "$taskName" -Confirm:$false

    # Remove user script
    Remove-Item -Path $uninstallScriptPath -Force
}

Exit $exitCode

Google Drive

Policy

SELECT name FROM programs WHERE name='Google Drive'

Install script

# Learn more about .exe install scripts:
# http://fleetdm.com/learn-more-about/exe-install-scripts

$exeFilePath = "${env:INSTALLER_PATH}"

try {

# Add argument to install silently
# Argument to make install silent depends on installer,
# each installer might use different argument (usually it's "/S" or "/s")
$processOptions = @{
  FilePath = "$exeFilePath"
  ArgumentList = "--silent --skip_launch_new --gsuite_shortcuts=false"
  PassThru = $true
  Wait = $true
}
    
# Start process and track exit code
$process = Start-Process @processOptions
$exitCode = $process.ExitCode

# Prints the exit code
Write-Host "Install exit code: $exitCode"
Exit $exitCode

} catch {
  Write-Host "Error: $_"
  Exit 1
}

Uninstall script

# Fleet extracts name from installer (EXE) and saves it to PACKAGE_ID
# variable
$softwareName = "Google Drive"

# It is recommended to use exact software name here if possible to avoid
# uninstalling unintended software.
$softwareNameLike = "*$softwareName*"

# Some uninstallers require a flag to run silently.
# Each uninstaller might use different argument (usually it's "/S" or "/s")
$uninstallArgs = "/S"

$machineKey = `
 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*'
$machineKey32on64 = `
 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'

$exitCode = 0

try {

[array]$uninstallKeys = Get-ChildItem `
    -Path @($machineKey, $machineKey32on64) `
    -ErrorAction SilentlyContinue |
        ForEach-Object { Get-ItemProperty $_.PSPath }

$foundUninstaller = $false
foreach ($key in $uninstallKeys) {
    # If needed, add -notlike to the comparison to exclude certain similar
    # software
    if ($key.DisplayName -like $softwareNameLike) {
        $foundUninstaller = $true
        # Get the uninstall command. Some uninstallers do not include
        # 'QuietUninstallString' and require a flag to run silently.
        $uninstallCommand = if ($key.QuietUninstallString) {
            $key.QuietUninstallString
        } else {
            $key.UninstallString
        }

        # The uninstall command may contain command and args, like:
        # "C:\Program Files\Software\uninstall.exe" --uninstall --silent
        # Split the command and args
        $splitArgs = $uninstallCommand.Split('"')
        if ($splitArgs.Length -gt 1) {
            if ($splitArgs.Length -eq 3) {
                $uninstallArgs = "$( $splitArgs[2] ) $uninstallArgs".Trim()
            } elseif ($splitArgs.Length -gt 3) {
                Throw `
                    "Uninstall command contains multiple quoted strings. " +
                        "Please update the uninstall script.`n" +
                        "Uninstall command: $uninstallCommand"
            }
            $uninstallCommand = $splitArgs[1]
        }
        Write-Host "Uninstall command: $uninstallCommand"
        Write-Host "Uninstall args: $uninstallArgs"

        $processOptions = @{
            FilePath = $uninstallCommand
            PassThru = $true
            Wait = $true
        }
        if ($uninstallArgs -ne '') {
            $processOptions.ArgumentList = "$uninstallArgs"
        }

        # Start process and track exit code
        $process = Start-Process @processOptions
        $exitCode = $process.ExitCode

        # Prints the exit code
        Write-Host "Uninstall exit code: $exitCode"
        # Exit the loop once the software is found and uninstalled.
        break
    }
}

if (-not $foundUninstaller) {
    Write-Host "Uninstaller for '$softwareName' not found."
    # Change exit code to 0 if you don't want to fail if uninstaller is not
    # found. This could happen if program was already uninstalled.
    $exitCode = 1
}

} catch {
    Write-Host "Error: $_"
    $exitCode = 1
}

Exit $exitCode

Microsoft Teams

Install script

$logFile = "${env:TEMP}/fleet-install-software.log"

try {

$installProcess = Start-Process msiexec.exe `
  -ArgumentList "/quiet /norestart ALLUSERS=1 /lv ${logFile} /i `"${env:INSTALLER_PATH}`"" `
  -PassThru -Verb RunAs -Wait

Get-Content $logFile -Tail 500

Exit $installProcess.ExitCode

} catch {
  Write-Host "Error: $_"
  Exit 1
}

Uninstall script

$product_code = "{731F6BAA-A986-45A4-8936-7C3AAAAA760B}"

# Fleet uninstalls app using product code that's extracted on upload
msiexec /quiet /x $product_code
Exit $LASTEXITCODE

Microsoft Office 365

Policy

SELECT name FROM programs WHERE name LIKE 'Microsoft 365 Apps for business%'

Install script

# Learn more about .exe install scripts:
# http://fleetdm.com/learn-more-about/exe-install-scripts

$exeFilePath = "${env:INSTALLER_PATH}"

try {

# Add argument to install silently
# Argument to make install silent depends on installer,
# each installer might use different argument (usually it's "/S" or "/s")
$processOptions = @{
  FilePath = "$exeFilePath"
  ArgumentList = "/S"
  PassThru = $true
  Wait = $true
}
    
# Start process and track exit code
$process = Start-Process @processOptions
$exitCode = $process.ExitCode

# Prints the exit code
Write-Host "Install exit code: $exitCode"
Exit $exitCode

} catch {
  Write-Host "Error: $_"
  Exit 1
}

Uninstall script

# Fleet extracts name from installer (EXE) and saves it to PACKAGE_ID
# variable
$softwareName = "Microsoft Office"

# It is recommended to use exact software name here if possible to avoid
# uninstalling unintended software.
$softwareNameLike = "*$softwareName*"

# Some uninstallers require a flag to run silently.
# Each uninstaller might use different argument (usually it's "/S" or "/s")
$uninstallArgs = "/S"

$machineKey = `
 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*'
$machineKey32on64 = `
 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'

$exitCode = 0

try {

[array]$uninstallKeys = Get-ChildItem `
    -Path @($machineKey, $machineKey32on64) `
    -ErrorAction SilentlyContinue |
        ForEach-Object { Get-ItemProperty $_.PSPath }

$foundUninstaller = $false
foreach ($key in $uninstallKeys) {
    # If needed, add -notlike to the comparison to exclude certain similar
    # software
    if ($key.DisplayName -like $softwareNameLike) {
        $foundUninstaller = $true
        # Get the uninstall command. Some uninstallers do not include
        # 'QuietUninstallString' and require a flag to run silently.
        $uninstallCommand = if ($key.QuietUninstallString) {
            $key.QuietUninstallString
        } else {
            $key.UninstallString
        }

        # The uninstall command may contain command and args, like:
        # "C:\Program Files\Software\uninstall.exe" --uninstall --silent
        # Split the command and args
        $splitArgs = $uninstallCommand.Split('"')
        if ($splitArgs.Length -gt 1) {
            if ($splitArgs.Length -eq 3) {
                $uninstallArgs = "$( $splitArgs[2] ) $uninstallArgs".Trim()
            } elseif ($splitArgs.Length -gt 3) {
                Throw `
                    "Uninstall command contains multiple quoted strings. " +
                        "Please update the uninstall script.`n" +
                        "Uninstall command: $uninstallCommand"
            }
            $uninstallCommand = $splitArgs[1]
        }
        Write-Host "Uninstall command: $uninstallCommand"
        Write-Host "Uninstall args: $uninstallArgs"

        $processOptions = @{
            FilePath = $uninstallCommand
            PassThru = $true
            Wait = $true
        }
        if ($uninstallArgs -ne '') {
            $processOptions.ArgumentList = "$uninstallArgs"
        }

        # Start process and track exit code
        $process = Start-Process @processOptions
        $exitCode = $process.ExitCode

        # Prints the exit code
        Write-Host "Uninstall exit code: $exitCode"
        # Exit the loop once the software is found and uninstalled.
        break
    }
}

if (-not $foundUninstaller) {
    Write-Host "Uninstaller for '$softwareName' not found."
    # Change exit code to 0 if you don't want to fail if uninstaller is not
    # found. This could happen if program was already uninstalled.
    $exitCode = 1
}

} catch {
    Write-Host "Error: $_"
    $exitCode = 1
}

Exit $exitCode

Did this answer your question?