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