├── nme ├── bicep │ └── nested_pid_8c1c30c0_3e0a_4655_9e05_51dea63a0e32_partnercenter.bicep └── terraform │ ├── _resources │ └── nerdio.png │ ├── sig.tf │ ├── providers.tf │ ├── versions.tf │ ├── rg.tf │ ├── private-dns.tf │ ├── data.tf │ ├── role-assignments.tf │ └── vnet.tf ├── actions ├── apps.png ├── core │ ├── Restart-Step.ps1 │ ├── 203_MicrosoftOutlook.ps1 │ ├── 100_MicrosoftVcRedists.ps1 │ ├── 012_WindowsUpdate.ps1 │ ├── 011_SupportFunctions.ps1 │ ├── 213_MicrosoftWindowsApp.ps1 │ ├── 103_MicrosoftNET.ps1 │ ├── 214_MicrosoftAzureCLI.ps1 │ ├── 215_MicrosoftPowerShell.ps1 │ └── 212_MicrosoftSQLServerManagementStudio.ps1 ├── tweaks │ ├── Invoke-DefenderFullScan.ps1 │ ├── Invoke-DefenderQuickScan.ps1 │ ├── Enable-TimeZoneRedirection.ps1 │ ├── Disable-FSLogixProfileContainer.ps1 │ ├── Disable-WindowsUpdate.ps1 │ ├── Set-WindowsUITweaks.ps1 │ ├── Enable-IgnoreRemoteKeyboardLayout.ps1 │ ├── Remove-IgnoreRemoteKeyboardLayout.ps1 │ ├── Remove-CitrixWorkspaceAppStartup.ps1 │ ├── Remove-WinRmRemoting.ps1 │ ├── Set-DefenderEndpointTag.ps1 │ ├── Remove-AdobeAcrobatReader.ps1 │ ├── Set-RdpFrameRate.ps1 │ ├── Remove-Directory.ps1 │ ├── Install-FSLogixAppMaskingRuleset.ps1 │ ├── Set-AppLockerPolicyConfig.ps1 │ └── Enable-RDPShortpath.ps1 ├── tools │ ├── Set-HybridAzureADJoin.ps1 │ ├── Uninstall-MicrosoftAzurePipelinesAgent.ps1 │ ├── Set-FSLogixStorageAccount.ps1 │ ├── Install-Pester.ps1 │ └── Install-MicrosoftAzurePipelinesAgent.ps1 ├── 3rdparty │ ├── 405_pdfforgePDFCreator.ps1 │ ├── 420_1Password.ps1 │ ├── 402_ZoomMeetings.ps1 │ ├── 411_draw.io.ps1 │ ├── 408_RemoteDesktopAnalyzer.ps1 │ └── 404_NotepadPlusPlus.ps1 └── optimise │ └── Remove-UScheduleKeys.ps1 ├── .vscode ├── extensions.json └── settings.json ├── .github ├── FUNDING.yml └── dependabot.yml ├── migrate └── img │ ├── citrix-installed.png │ ├── citrix-noagents.png │ ├── omnissa-installed.png │ ├── omnissa-noagents.png │ ├── microsoft-installed.png │ ├── uninstall-citrixagents.png │ └── uninstall-omnissaagents.png ├── variables ├── SecureVars.json ├── README.md ├── locale.json └── NerdioManagerVariables.json ├── apps ├── configs │ ├── AppLockerRules-20231114-0803-Enforce.xml │ └── Redirections.xml └── appv │ ├── Install-JGraphDrawIO.ps1 │ ├── Install-ImageGlass.ps1 │ ├── Install-NotepadPlusPlus.ps1 │ ├── Install-VLCMediaPlayer.ps1 │ ├── Install-Paint.NET.ps1 │ ├── Install-FoxitPDFReader.ps1 │ └── Install-Greenshot.ps1 ├── shell-apps ├── Microsoft │ ├── AptosFont │ │ ├── Uninstall.ps1 │ │ ├── Detect.ps1 │ │ └── Definition.json │ ├── WindowsApp │ │ ├── Install.ps1 │ │ ├── Uninstall.ps1 │ │ ├── Definition.json │ │ └── Detect.ps1 │ ├── NETLTS │ │ ├── Install.ps1 │ │ ├── Definition.json │ │ ├── Detect.ps1 │ │ └── Uninstall.ps1 │ ├── VisualC++2022x64 │ │ ├── Install.ps1 │ │ ├── Definition.json │ │ └── Uninstall.ps1 │ ├── VisualC++2022x86 │ │ ├── Install.ps1 │ │ ├── Definition.json │ │ └── Uninstall.ps1 │ ├── SQLServerManagementStudio │ │ ├── Install.ps1 │ │ ├── Definition.json │ │ ├── Detect.ps1 │ │ └── Uninstall.ps1 │ ├── EdgeWebView2 │ │ ├── Install.ps1 │ │ ├── Definition.json │ │ ├── Detect.ps1 │ │ └── Uninstall.ps1 │ ├── VisualStudioCode │ │ ├── Install.ps1 │ │ ├── Definition.json │ │ ├── Detect.ps1 │ │ └── Uninstall.ps1 │ ├── SupportCenter │ │ ├── Install.ps1 │ │ ├── Definition.json │ │ ├── Uninstall.ps1 │ │ └── Detect.ps1 │ ├── PowerShell │ │ ├── Install.ps1 │ │ ├── Definition.json │ │ ├── Detect.ps1 │ │ └── Uninstall.ps1 │ ├── AvdRtcService │ │ ├── Install.ps1 │ │ ├── Definition.json │ │ ├── Uninstall.ps1 │ │ └── Detect.ps1 │ ├── AzureCLI │ │ ├── Install.ps1 │ │ ├── Definition.json │ │ ├── Detect.ps1 │ │ └── Uninstall.ps1 │ ├── AvdMultimediaRedirection │ │ ├── Install.ps1 │ │ ├── Definition.json │ │ ├── Detect.ps1 │ │ └── Uninstall.ps1 │ ├── Edge │ │ ├── Uninstall.ps1 │ │ ├── Definition.json │ │ └── Detect.ps1 │ ├── Teams │ │ ├── Definition.json │ │ ├── Detect.ps1 │ │ └── Uninstall.ps1 │ ├── OneDrive │ │ ├── Definition.json │ │ ├── Install.ps1 │ │ └── Uninstall.ps1 │ ├── PowerToys │ │ ├── Definition.json │ │ ├── Detect.ps1 │ │ └── Uninstall.ps1 │ └── FSLogixApps │ │ ├── Definition.json │ │ ├── Install.ps1 │ │ ├── Detect.ps1 │ │ └── Uninstall.ps1 ├── stealthpuppy │ └── defaults │ │ ├── Uninstall.ps1 │ │ ├── Install.ps1 │ │ ├── Definition.json │ │ └── Detect.ps1 ├── Audacity │ ├── Install.ps1 │ ├── Definition.json │ ├── Uninstall.ps1 │ └── Detect.ps1 ├── Zoom │ └── Workplace │ │ ├── Install.ps1 │ │ ├── Definition.json │ │ ├── Uninstall.ps1 │ │ └── Detect.ps1 ├── README.md ├── Obsidian │ ├── Install.ps1 │ ├── Definition.json │ ├── Uninstall.ps1 │ └── Detect.ps1 ├── dotPDN │ └── Paint.NET │ │ ├── Install.ps1 │ │ ├── Definition.json │ │ ├── Uninstall.ps1 │ │ └── Detect.ps1 ├── JGraph │ └── draw.io │ │ ├── Install.ps1 │ │ ├── Definition.json │ │ ├── Uninstall.ps1 │ │ └── Detect.ps1 ├── Foxit │ └── PDFReader │ │ ├── Definition.json │ │ ├── Install.ps1 │ │ ├── Uninstall.ps1 │ │ └── Detect.ps1 ├── Google │ └── Chrome │ │ ├── Definition.json │ │ ├── Uninstall.ps1 │ │ └── Detect.ps1 ├── Adobe │ └── AcrobatReader │ │ ├── Definition.json │ │ ├── Uninstall.ps1 │ │ └── Detect.ps1 └── ImageGlass │ ├── Definition.json │ ├── Install.ps1 │ ├── Uninstall.ps1 │ └── Detect.ps1 ├── import └── Detect.json ├── .devops └── pipelines │ └── validate-apps.yml ├── README.md └── .gitignore /nme/bicep/nested_pid_8c1c30c0_3e0a_4655_9e05_51dea63a0e32_partnercenter.bicep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /actions/apps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronparker/nerdio-actions/HEAD/actions/apps.png -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "ms-vscode.powershell" 4 | ] 5 | } -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: aaronparker 4 | ko_fi: stealthpuppy 5 | -------------------------------------------------------------------------------- /migrate/img/citrix-installed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronparker/nerdio-actions/HEAD/migrate/img/citrix-installed.png -------------------------------------------------------------------------------- /migrate/img/citrix-noagents.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronparker/nerdio-actions/HEAD/migrate/img/citrix-noagents.png -------------------------------------------------------------------------------- /migrate/img/omnissa-installed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronparker/nerdio-actions/HEAD/migrate/img/omnissa-installed.png -------------------------------------------------------------------------------- /migrate/img/omnissa-noagents.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronparker/nerdio-actions/HEAD/migrate/img/omnissa-noagents.png -------------------------------------------------------------------------------- /migrate/img/microsoft-installed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronparker/nerdio-actions/HEAD/migrate/img/microsoft-installed.png -------------------------------------------------------------------------------- /nme/terraform/_resources/nerdio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronparker/nerdio-actions/HEAD/nme/terraform/_resources/nerdio.png -------------------------------------------------------------------------------- /migrate/img/uninstall-citrixagents.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronparker/nerdio-actions/HEAD/migrate/img/uninstall-citrixagents.png -------------------------------------------------------------------------------- /migrate/img/uninstall-omnissaagents.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronparker/nerdio-actions/HEAD/migrate/img/uninstall-omnissaagents.png -------------------------------------------------------------------------------- /variables/SecureVars.json: -------------------------------------------------------------------------------- 1 | { 2 | "VariablesList": "https://stybluynyickph2.blob.core.windows.net/variables/NerdioManagerVariables.json" 3 | } -------------------------------------------------------------------------------- /actions/core/Restart-Step.ps1: -------------------------------------------------------------------------------- 1 | #description: Installs the latest Microsoft PowerShell 2 | #execution mode: IndividualWithRestart 3 | #tags: Image, Restart 4 | -------------------------------------------------------------------------------- /apps/configs/AppLockerRules-20231114-0803-Enforce.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronparker/nerdio-actions/HEAD/apps/configs/AppLockerRules-20231114-0803-Enforce.xml -------------------------------------------------------------------------------- /shell-apps/Microsoft/AptosFont/Uninstall.ps1: -------------------------------------------------------------------------------- 1 | Get-ChildItem -Path "$Env:SystemRoot\Fonts\Aptos*" | ForEach-Object { 2 | $Context.Log("Removing font file: $($_.FullName)") 3 | Remove-Item -Path $_.FullName -Force -ErrorAction "SilentlyContinue" 4 | } 5 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # Set update schedule for GitHub Actions 2 | version: 2 3 | updates: 4 | - package-ecosystem: "github-actions" 5 | directory: "/" 6 | schedule: 7 | # Check for updates to GitHub Actions every weekday 8 | interval: "daily" 9 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/WindowsApp/Install.ps1: -------------------------------------------------------------------------------- 1 | $params = @{ 2 | PackagePath = $Context.GetAttachedBinary() 3 | Online = $true 4 | SkipLicense = $true 5 | ErrorAction = "Stop" 6 | } 7 | Add-AppxProvisionedPackage @params 8 | $Context.Log("Install complete") 9 | -------------------------------------------------------------------------------- /shell-apps/stealthpuppy/defaults/Uninstall.ps1: -------------------------------------------------------------------------------- 1 | $Context.Log("Uninstalling Windows Enterprise Defaults") 2 | Get-ChildItem -Path $PWD -Include "Remove-Defaults.ps1" -Recurse -File | ForEach-Object { 3 | $Context.Log("Executing: $($_.FullName)") 4 | & $_.FullName 5 | } 6 | $Context.Log("Uninstall complete") 7 | -------------------------------------------------------------------------------- /actions/tweaks/Invoke-DefenderFullScan.ps1: -------------------------------------------------------------------------------- 1 | #description: Runs a Microsoft Defender antivirus quick scan. Use in a desktop image to ensure the scan data is up to date 2 | #execution mode: Combined 3 | #tags: Antivirus, Image 4 | 5 | Update-MpSignature -UpdateSource "MicrosoftUpdateServer" 6 | Start-MpScan -ScanType "FullScan" 7 | -------------------------------------------------------------------------------- /actions/tweaks/Invoke-DefenderQuickScan.ps1: -------------------------------------------------------------------------------- 1 | #description: Runs a Microsoft Defender antivirus quick scan. Use in a desktop image to ensure the scan data is up to date 2 | #execution mode: Combined 3 | #tags: Antivirus, Image 4 | 5 | Update-MpSignature -UpdateSource "MicrosoftUpdateServer" 6 | Start-MpScan -ScanType "QuickScan" 7 | -------------------------------------------------------------------------------- /nme/terraform/sig.tf: -------------------------------------------------------------------------------- 1 | resource "azurerm_shared_image_gallery" "nerdio" { 2 | name = "${lower(replace(var.base_name, "-", ""))}sig" 3 | resource_group_name = local.resource_group_name 4 | location = local.resource_group_location 5 | description = "Images for Virtual Desktops" 6 | 7 | tags = var.tags 8 | } 9 | -------------------------------------------------------------------------------- /variables/README.md: -------------------------------------------------------------------------------- 1 | # Example Variable 2 | 3 | Files are are example variable data used by some scripts. 4 | 5 | To format the JSON data for pasting into the Nerdio Manager secure variables values, use the following to compress the JSON. 6 | 7 | ```powershell 8 | Get-Content -Path ./locale.json | ConvertFrom-Json | ConvertTo-Json -Compress | Set-Clipboard 9 | ``` 10 | -------------------------------------------------------------------------------- /actions/tweaks/Enable-TimeZoneRedirection.ps1: -------------------------------------------------------------------------------- 1 | #description: Enable time zone redirection in RDP sessions 2 | #execution mode: Combined 3 | #tags: Keyboard, Language, Image 4 | 5 | # Enable time zone redirection - this can be configure via policy as well 6 | reg add "HKLM\Software\Policies\Microsoft\Windows NT\Terminal Services" /v fEnableTimeZoneRedirection /d 1 /t REG_DWORD /f 7 | -------------------------------------------------------------------------------- /actions/tweaks/Disable-FSLogixProfileContainer.ps1: -------------------------------------------------------------------------------- 1 | #description: Disables the Microsoft FSLogix Profile Container. Reboot required. 2 | #execution mode: Combined 3 | #tags: FSLogix, Image 4 | 5 | # https://learn.microsoft.com/en-us/fslogix/reference-configuration-settings?tabs=profiles#enabled 6 | reg add "HKLM\SOFTWARE\FSLogix\Profiles" /v "Enabled" /t "REG_DWORD" /d 0 /f | Out-Null 7 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/NETLTS/Install.ps1: -------------------------------------------------------------------------------- 1 | $params = @{ 2 | FilePath = $Context.GetAttachedBinary() 3 | ArgumentList = "/install /quiet /norestart" 4 | Wait = $true 5 | PassThru = $true 6 | NoNewWindow = $true 7 | ErrorAction = "Stop" 8 | } 9 | $result = Start-Process @params 10 | $Context.Log("Install complete. Return code: $($result.ExitCode)") 11 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/VisualC++2022x64/Install.ps1: -------------------------------------------------------------------------------- 1 | $params = @{ 2 | FilePath = $Context.GetAttachedBinary() 3 | ArgumentList = "/install /passive /norestart" 4 | Wait = $true 5 | NoNewWindow = $true 6 | PassThru = $true 7 | ErrorAction = "Stop" 8 | } 9 | $result = Start-Process @params 10 | $Context.Log("Install complete. Return code: $($result.ExitCode)") 11 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/VisualC++2022x86/Install.ps1: -------------------------------------------------------------------------------- 1 | $params = @{ 2 | FilePath = $Context.GetAttachedBinary() 3 | ArgumentList = "/install /passive /norestart" 4 | Wait = $true 5 | NoNewWindow = $true 6 | PassThru = $true 7 | ErrorAction = "Stop" 8 | } 9 | $result = Start-Process @params 10 | $Context.Log("Install complete. Return code: $($result.ExitCode)") 11 | -------------------------------------------------------------------------------- /actions/tweaks/Disable-WindowsUpdate.ps1: -------------------------------------------------------------------------------- 1 | #description: Disables Windows Update 2 | #execution mode: Combined 3 | #tags: Update, Image 4 | 5 | $RegPath = "HKLM:\Software\Policies\Microsoft\Windows\WindowsUpdate\AU" 6 | if (-not (Test-Path -Path $RegPath)) { New-Item -Path $RegPath -Force } 7 | Set-ItemProperty -Path $RegPath -Name NoAutoUpdate -Value 1 8 | Set-ItemProperty -Path $RegPath -Name AUOptions -Value 3 9 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/SQLServerManagementStudio/Install.ps1: -------------------------------------------------------------------------------- 1 | $params = @{ 2 | FilePath = $Context.GetAttachedBinary() 3 | ArgumentList = "/install /quiet /norestart" 4 | Wait = $true 5 | PassThru = $true 6 | NoNewWindow = $true 7 | ErrorAction = "Stop" 8 | } 9 | $result = Start-Process @params 10 | $Context.Log("Install complete. Return code: $($result.ExitCode)") 11 | -------------------------------------------------------------------------------- /actions/tweaks/Set-WindowsUITweaks.ps1: -------------------------------------------------------------------------------- 1 | #description: Configure Windows UI settings 2 | #execution mode: Combined 3 | #tags: UI 4 | 5 | # Add registry keys 6 | reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes" /v "MS Shell Dlg" /t "REG_SZ" /d "Tahoma" /f | Out-Null 7 | reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes" /v "MS Shell Dlg 2" /t "REG_SZ" /d "Tahoma" /f | Out-Null 8 | -------------------------------------------------------------------------------- /shell-apps/Audacity/Install.ps1: -------------------------------------------------------------------------------- 1 | $params = @{ 2 | FilePath = $Context.GetAttachedBinary() 3 | ArgumentList = "/VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP- /MERGETASKS=`"!desktopicon`"" 4 | Wait = $true 5 | PassThru = $true 6 | NoNewWindow = $true 7 | ErrorAction = "Stop" 8 | } 9 | $result = Start-Process @params 10 | $Context.Log("Install complete. Return code: $($result.ExitCode)") 11 | -------------------------------------------------------------------------------- /nme/terraform/providers.tf: -------------------------------------------------------------------------------- 1 | 2 | provider "azurerm" { 3 | storage_use_azuread = true 4 | features { 5 | application_insights { 6 | disable_generated_rule = true 7 | } 8 | key_vault { 9 | purge_soft_delete_on_destroy = true 10 | recover_soft_deleted_key_vaults = true 11 | } 12 | log_analytics_workspace { 13 | permanently_delete_on_destroy = true 14 | } 15 | } 16 | } 17 | 18 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/EdgeWebView2/Install.ps1: -------------------------------------------------------------------------------- 1 | $Context.Log("Installing package: $($Context.GetAttachedBinary())") 2 | $params = @{ 3 | FilePath = $Context.GetAttachedBinary() 4 | ArgumentList = "/silent /install" 5 | Wait = $true 6 | PassThru = $true 7 | NoNewWindow = $true 8 | ErrorAction = "Stop" 9 | } 10 | $result = Start-Process @params 11 | $Context.Log("Install complete. Return code: $($result.ExitCode)") 12 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/WindowsApp/Uninstall.ps1: -------------------------------------------------------------------------------- 1 | # Variables 2 | [System.String] $PackageFamilyName = "MicrosoftCorporationII.Windows365_8wekyb3d8bbwe" 3 | 4 | Get-AppxPackage -AllUsers | Where-Object { $_.PackageFamilyName -eq $PackageFamilyName } | ForEach-Object { 5 | $Context.Log("Removing existing AppX package: $($_.Name)") 6 | $_ | Remove-AppxPackage -AllUsers -ErrorAction "Stop" 7 | } 8 | Start-Sleep -Seconds 10 9 | $Context.Log("Uninstall complete") 10 | -------------------------------------------------------------------------------- /actions/tweaks/Enable-IgnoreRemoteKeyboardLayout.ps1: -------------------------------------------------------------------------------- 1 | #description: Ignore the keyboard layout of the endpoint and keep the selected input language in the AVD session host 2 | #execution mode: Combined 3 | #tags: Keyboard, Language, Image 4 | 5 | # Add the registry value 6 | # https://dennisspan.com/solving-keyboard-layout-issues-in-an-ica-or-rdp-session/ 7 | reg add "HKLM\SYSTEM\CurrentControlSet\Control\Keyboard Layout" /v "IgnoreRemoteKeyboardLayout" /d 1 /t "REG_DWORD" /f 8 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/VisualStudioCode/Install.ps1: -------------------------------------------------------------------------------- 1 | $params = @{ 2 | FilePath = $Context.GetAttachedBinary() 3 | ArgumentList = "/VERYSILENT /NOCLOSEAPPLICATIONS /NORESTARTAPPLICATIONS /NORESTART /SP- /SUPPRESSMSGBOXES /MERGETASKS=!runcode" 4 | Wait = $true 5 | NoNewWindow = $true 6 | PassThru = $true 7 | ErrorAction = "Stop" 8 | } 9 | $result = Start-Process @params 10 | $Context.Log("Install complete. Return code: $($result.ExitCode)") 11 | -------------------------------------------------------------------------------- /actions/tweaks/Remove-IgnoreRemoteKeyboardLayout.ps1: -------------------------------------------------------------------------------- 1 | #description: Removes the setting to ignore the keyboard layout of the endpoint and keep the selected input language in the AVD session host 2 | #execution mode: Combined 3 | #tags: Keyboard, Language, Image 4 | 5 | # Remove the registry value 6 | # https://dennisspan.com/solving-keyboard-layout-issues-in-an-ica-or-rdp-session/ 7 | reg delete "HKLM\SYSTEM\CurrentControlSet\Control\Keyboard Layout" /v "IgnoreRemoteKeyboardLayout" /f | Out-Null 8 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/SupportCenter/Install.ps1: -------------------------------------------------------------------------------- 1 | $Context.Log("Installing package: $($Context.GetAttachedBinary())") 2 | $params = @{ 3 | FilePath = "$Env:SystemRoot\System32\msiexec.exe" 4 | ArgumentList = "/package `"$($Context.GetAttachedBinary())`" /quiet" 5 | Wait = $true 6 | NoNewWindow = $true 7 | PassThru = $true 8 | ErrorAction = "Stop" 9 | } 10 | $result = Start-Process @params 11 | $Context.Log("Install complete. Return code: $($result.ExitCode)") 12 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/PowerShell/Install.ps1: -------------------------------------------------------------------------------- 1 | $Context.Log("Installing package: $($Context.GetAttachedBinary())") 2 | $params = @{ 3 | FilePath = "$Env:SystemRoot\System32\msiexec.exe" 4 | ArgumentList = "/package $($Context.GetAttachedBinary()) /quiet /norestart" 5 | Wait = $true 6 | PassThru = $true 7 | NoNewWindow = $true 8 | ErrorAction = "Stop" 9 | } 10 | $result = Start-Process @params 11 | $Context.Log("Install complete. Return code: $($result.ExitCode)") 12 | -------------------------------------------------------------------------------- /actions/tweaks/Remove-CitrixWorkspaceAppStartup.ps1: -------------------------------------------------------------------------------- 1 | #description: Remove the Citrix Workspace app processes from the Run registry key 2 | #execution mode: Combined 3 | #tags: Citrix 4 | 5 | reg delete "HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Run" /v "AnalyticsSrv" /f | Out-Null 6 | reg delete "HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Run" /v "ConnectionCenter" /f | Out-Null 7 | reg delete "HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Run" /v "Redirector" /f | Out-Null 8 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/AvdRtcService/Install.ps1: -------------------------------------------------------------------------------- 1 | $Context.Log("Installing package: $($Context.GetAttachedBinary())") 2 | $params = @{ 3 | FilePath = "$Env:SystemRoot\System32\msiexec.exe" 4 | ArgumentList = "/package `"$($Context.GetAttachedBinary())`" /quiet /norestart" 5 | Wait = $true 6 | NoNewWindow = $true 7 | PassThru = $true 8 | ErrorAction = "Stop" 9 | } 10 | $result = Start-Process @params 11 | $Context.Log("Install complete. Return code: $($result.ExitCode)") 12 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/AzureCLI/Install.ps1: -------------------------------------------------------------------------------- 1 | $Context.Log("Installing package: $($Context.GetAttachedBinary())") 2 | $params = @{ 3 | FilePath = "$Env:SystemRoot\System32\msiexec.exe" 4 | ArgumentList = "/package $($Context.GetAttachedBinary()) /quiet /norestart ALLUSERS=1" 5 | Wait = $true 6 | PassThru = $true 7 | NoNewWindow = $true 8 | ErrorAction = "Stop" 9 | } 10 | $result = Start-Process @params 11 | $Context.Log("Install complete. Return code: $($result.ExitCode)") 12 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/AvdMultimediaRedirection/Install.ps1: -------------------------------------------------------------------------------- 1 | $Context.Log("Installing package: $($Context.GetAttachedBinary())") 2 | $params = @{ 3 | FilePath = "$Env:SystemRoot\System32\msiexec.exe" 4 | ArgumentList = "/package `"$($Context.GetAttachedBinary())`" /quiet /norestart" 5 | Wait = $true 6 | NoNewWindow = $true 7 | PassThru = $true 8 | ErrorAction = "Stop" 9 | } 10 | $result = Start-Process @params 11 | $Context.Log("Install complete. Return code: $($result.ExitCode)") 12 | -------------------------------------------------------------------------------- /actions/tweaks/Remove-WinRmRemoting.ps1: -------------------------------------------------------------------------------- 1 | #description: Disables WinRM firewall rules and PS Remoting. Only use if you need to disable these features 2 | #execution mode: Combined 3 | #tags: Language, Image 4 | 5 | #region Disable WinRM firewall rules and disable PS Remoting 6 | # https://github.com/Azure/RDS-Templates/issues/435 7 | # https://qiita.com/fujinon1109/items/440c614338fe2535b09e 8 | 9 | Get-NetFirewallRule -DisplayGroup "Windows Remote Management" | Disable-NetFirewallRule 10 | Disable-PSRemoting -Force 11 | #endregion 12 | -------------------------------------------------------------------------------- /shell-apps/Zoom/Workplace/Install.ps1: -------------------------------------------------------------------------------- 1 | $Context.Log("Installing package: $($Context.GetAttachedBinary())") 2 | $params = @{ 3 | FilePath = "$Env:SystemRoot\System32\msiexec.exe" 4 | ArgumentList = "/package `"$($Context.GetAttachedBinary())`" zSilentStart=false zNoDesktopShortCut=true ALLUSERS=1 /quiet" 5 | Wait = $true 6 | PassThru = $true 7 | NoNewWindow = $true 8 | ErrorAction = "Stop" 9 | } 10 | $result = Start-Process @params 11 | $Context.Log("Install complete. Return code: $($result.ExitCode)") 12 | -------------------------------------------------------------------------------- /nme/terraform/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.3" 3 | 4 | required_providers { 5 | azuread = { 6 | source = "hashicorp/azuread" 7 | version = "~> 2.31" 8 | } 9 | 10 | azurerm = { 11 | source = "hashicorp/azurerm" 12 | version = "~> 3.36" 13 | } 14 | 15 | time = { 16 | source = "hashicorp/time" 17 | version = "~> 0.9" 18 | } 19 | 20 | azapi = { 21 | source = "azure/azapi" 22 | version = "~> 1.10.0" 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /actions/tweaks/Set-DefenderEndpointTag.ps1: -------------------------------------------------------------------------------- 1 | #description: Sets a tag for Microsoft Defender for Endpoint 2 | #execution mode: Combined 3 | #tags: MDE 4 | 5 | # https://learn.microsoft.com/en-us/microsoft-365/security/defender-endpoint/machine-tags?view=o365-worldwide 6 | 7 | # Set a tag value 8 | if ($null -eq $SecureVars.MdeTag) { 9 | $TagValue = "AVD" 10 | } 11 | else { 12 | $TagValue = $SecureVars.MdeTag 13 | } 14 | 15 | # Add the tag value to the registry 16 | reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows Advanced Threat Protection\DeviceTagging" /v "Group" /t "REG_SZ" /d $TagValue /f | Out-Null 17 | -------------------------------------------------------------------------------- /actions/tweaks/Remove-AdobeAcrobatReader.ps1: -------------------------------------------------------------------------------- 1 | #description: Removes policies that Adobe Acrobat into read-only mode so that it runs as Reader 2 | #execution mode: Combined 3 | #tags: Adobe, Acrobat, PDF 4 | 5 | # https://helpx.adobe.com/au/enterprise/kb/acrobat-64-bit-for-enterprises.html 6 | reg delete "HKLM\SOFTWARE\Policies\Adobe\Adobe Acrobat\DC\FeatureLockDown" /v "bIsSCReducedModeEnforcedEx" /f | Out-Null 7 | reg delete "HKLM\SOFTWARE\Policies\Adobe\Adobe Acrobat\DC\FeatureLockDown\cIPM" /v "bDontShowMsgWhenViewingDoc" /f | Out-Null 8 | reg delete "HKLM\SOFTWARE\Policies\Adobe\Adobe Acrobat\DC\FeatureLockDown" /v "bAcroSuppressUpsell" /f | Out-Null 9 | -------------------------------------------------------------------------------- /actions/tweaks/Set-RdpFrameRate.ps1: -------------------------------------------------------------------------------- 1 | #description: Set a specified framerate for RDP - sets framerate to 60 FPS by default, unless RdpFrameRate is passed via Secure Variables 2 | #execution mode: Combined 3 | #tags: RDP, Framerate 4 | 5 | # https://learn.microsoft.com/en-us/troubleshoot/windows-server/remote/frame-rate-limited-to-30-fps 6 | 7 | if ($null -eq $SecureVars.RdpFrameRate) { 8 | $RdpFrameRate = "15" 9 | } 10 | else { 11 | $RdpFrameRate = $SecureVars.RdpFrameRate 12 | } 13 | 14 | # Add registry keys 15 | reg add "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations" /v "DWMFRAMEINTERVAL" /t "REG_DWORD" /d $RdpFrameRate /f | Out-Null 16 | -------------------------------------------------------------------------------- /shell-apps/README.md: -------------------------------------------------------------------------------- 1 | # Nerdio Manager Shell Apps 2 | 3 | Note: this code is provided as-is, without warranty or support of any kind. 4 | 5 | A list of definitions for Nerdio Manager Shell Apps - these include detection, install and uninstall scripts. 6 | 7 | ## Automation 8 | 9 | Included here is a proof-of-concept for automating the import for Shell Apps and versions - requires Nerdio Manager for Enterprise 7.2+: 10 | 11 | * `NerdioShellApps.psm1` - a module with functions required for automating the import of Shell Apps. This depends on the [Evergreen](https://stealthpuppy.com/evergreen) 12 | * `Create-ShellApps.ps1` - a sample script for importing a selection of Shell Apps into Nerdio Manager 13 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.words": [ 3 | "Addin", 4 | "ALLUSER", 5 | "Audiosrv", 6 | "AUTOACTIVATE", 7 | "bigendianunicode", 8 | "captutre", 9 | "CHROMEEXT", 10 | "Codecov", 11 | "DISABLEDESKTOPSHORTCUT", 12 | "DONOTCREATEDESKTOPSHORTCUT", 13 | "DWORD", 14 | "Foxit", 15 | "Greenshot", 16 | "HKEY", 17 | "Hotfixes", 18 | "Lync", 19 | "Nerdio", 20 | "Omnissa", 21 | "RUNAPPLICATION", 22 | "Shortpath", 23 | "THUMBNAILPREVIEW", 24 | "windowsdesktop", 25 | "Zstandard", 26 | "zyborg" 27 | ], 28 | "pester.autoRunOnSave": false 29 | } -------------------------------------------------------------------------------- /shell-apps/Microsoft/AptosFont/Detect.ps1: -------------------------------------------------------------------------------- 1 | # Variables 2 | [System.String] $FilePath = "$Env:SystemRoot\Fonts\Aptos.ttf" 3 | 4 | # Detection logic 5 | if ([System.String]::IsNullOrEmpty($Context.TargetVersion)) { 6 | # This should be an uninstall action 7 | if (Test-Path -Path $FilePath) { return $true } 8 | else { 9 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 10 | } 11 | } 12 | else { 13 | if (Test-Path -Path $FilePath) { 14 | return $Context.TargetVersion 15 | } 16 | else { 17 | $Context.Log("File does not exist at: $($FilePath)") 18 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /shell-apps/Obsidian/Install.ps1: -------------------------------------------------------------------------------- 1 | $params = @{ 2 | FilePath = $Context.GetAttachedBinary() 3 | ArgumentList = "/S /ALLUSERS=1 /D=`"${Env:ProgramFiles}\Obsidian`"" 4 | Wait = $true 5 | PassThru = $true 6 | NoNewWindow = $true 7 | ErrorAction = "Stop" 8 | } 9 | $result = Start-Process @params 10 | $Context.Log("Install complete. Return code: $($result.ExitCode)") 11 | 12 | # Delete public desktop shortcut 13 | Start-Sleep -Seconds 5 14 | $Shortcuts = @("$Env:Public\Desktop\Obsidian.lnk") 15 | Get-Item -Path $Shortcuts -ErrorAction "SilentlyContinue" | ` 16 | ForEach-Object { $Context.Log("Remove file: $($_.FullName)"); Remove-Item -Path $_.FullName -Force -ErrorAction "SilentlyContinue" } 17 | -------------------------------------------------------------------------------- /nme/terraform/rg.tf: -------------------------------------------------------------------------------- 1 | resource "azurerm_resource_group" "nerdio" { 2 | count = var.create_resource_group ? 1 : 0 3 | name = var.resource_group_name != "" ? var.resource_group_name : "${lower(var.base_name)}-rg" 4 | location = var.location 5 | tags = var.tags 6 | } 7 | 8 | data "azurerm_resource_group" "existing" { 9 | count = var.create_resource_group ? 0 : 1 10 | name = var.resource_group_name 11 | } 12 | 13 | locals { 14 | resource_group_name = var.create_resource_group ? azurerm_resource_group.nerdio[0].name : data.azurerm_resource_group.existing[0].name 15 | resource_group_location = var.create_resource_group ? azurerm_resource_group.nerdio[0].location : data.azurerm_resource_group.existing[0].location 16 | } 17 | -------------------------------------------------------------------------------- /actions/tools/Set-HybridAzureADJoin.ps1: -------------------------------------------------------------------------------- 1 | #description: Enables Hybrid Entra ID join registry entries 2 | #execution mode: Combined 3 | #tags: Image, HAADJ 4 | 5 | # https://learn.microsoft.com/en-us/azure/active-directory/devices/hybrid-azuread-join-control 6 | 7 | if ($null -eq $SecureVars.AzureADTenantName) { 8 | throw "AzureADTenantName not set" 9 | } 10 | 11 | if ($null -eq $SecureVars.AzureADTenantId) { 12 | throw "AzureADTenantId not set" 13 | } 14 | 15 | # Add registry keys 16 | reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\CDJ\AAD" /v "TenantName" /t "REG_SZ" /d $SecureVars.AzureADTenantName /f | Out-Null 17 | reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\CDJ\AAD" /v "TenantId" /t "REG_SZ" /d $SecureVars.AzureADTenantId /f | Out-Null 18 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/Edge/Uninstall.ps1: -------------------------------------------------------------------------------- 1 | # Warning - uninstalling Microsoft Edge is probably not a good idea, but this is how you do it. 2 | 3 | # Uninstall Microsoft Edge using the setup.exe in the Edge application directory 4 | $SetupExe = Get-ChildItem -Path "${Env:ProgramFiles(x86)}\Microsoft\Edge\Application" -Recurse -Include "setup.exe" | ` 5 | Select-Object -First 1 6 | 7 | $params = @{ 8 | FilePath = $SetupExe.FullName 9 | ArgumentList = "setup.exe --uninstall --system-level --verbose-logging --force-uninstall" 10 | Wait = $true 11 | PassThru = $true 12 | NoNewWindow = $true 13 | ErrorAction = "Stop" 14 | } 15 | $result = Start-Process @params 16 | $Context.Log("Uninstall complete. Return code: $($result.ExitCode)") 17 | -------------------------------------------------------------------------------- /shell-apps/dotPDN/Paint.NET/Install.ps1: -------------------------------------------------------------------------------- 1 | Get-ChildItem -Path $PWD -Recurse -Include "paint.*msi" | ForEach-Object { 2 | $Context.Log("Installing Paint.NET from: $($_.FullName)") 3 | $params = @{ 4 | FilePath = "$Env:SystemRoot\System32\msiexec.exe" 5 | ArgumentList = "/package `"$($_.FullName)`" DESKTOPSHORTCUT=0 CHECKFORUPDATES=0 CHECKFORBETAS=0 /quiet" 6 | Wait = $true 7 | NoNewWindow = $true 8 | PassThru = $true 9 | ErrorAction = "Stop" 10 | } 11 | $result = Start-Process @params 12 | $Context.Log("Install complete. Return code: $($result.ExitCode)") 13 | } 14 | 15 | Start-Sleep -Seconds 5 16 | $Shortcuts = @("$Env:Public\Desktop\Paint.NET.lnk") 17 | Remove-Item -Path $Shortcuts -Force -ErrorAction "Ignore" 18 | -------------------------------------------------------------------------------- /shell-apps/stealthpuppy/defaults/Install.ps1: -------------------------------------------------------------------------------- 1 | # Configure the environment 2 | $ErrorActionPreference = [System.Management.Automation.ActionPreference]::Stop 3 | $InformationPreference = [System.Management.Automation.ActionPreference]::Continue 4 | $ProgressPreference = [System.Management.Automation.ActionPreference]::SilentlyContinue 5 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072 6 | 7 | # Unzip and run all Install-Defaults.ps1 scripts 8 | Expand-Archive -Path $Context.GetAttachedBinary() -DestinationPath $PWD -Force 9 | Get-ChildItem -Path $PWD -Include "Install-Defaults.ps1" -Recurse -File | ForEach-Object { 10 | $Context.Log("Executing: $($_.FullName)") 11 | & $_.FullName 12 | } 13 | $Context.Log("Install complete") 14 | -------------------------------------------------------------------------------- /shell-apps/JGraph/draw.io/Install.ps1: -------------------------------------------------------------------------------- 1 | $Context.Log("Installing package: $($Context.GetAttachedBinary())") 2 | $params = @{ 3 | FilePath = "$Env:SystemRoot\System32\msiexec.exe" 4 | ArgumentList = "/package $($Context.GetAttachedBinary()) /quiet /norestart ALLUSERS=1" 5 | Wait = $true 6 | PassThru = $true 7 | NoNewWindow = $true 8 | ErrorAction = "Stop" 9 | } 10 | $result = Start-Process @params 11 | $Context.Log("Install complete. Return code: $($result.ExitCode)") 12 | 13 | # Post install configuration 14 | $Shortcuts = @("$Env:Public\Desktop\draw.io.lnk") 15 | Get-Item -Path $Shortcuts -ErrorAction "SilentlyContinue" | ` 16 | ForEach-Object { $Context.Log("Remove file: $($_.FullName)"); Remove-Item -Path $_.FullName -Force -ErrorAction "SilentlyContinue" } 17 | -------------------------------------------------------------------------------- /actions/tweaks/Remove-Directory.ps1: -------------------------------------------------------------------------------- 1 | #description: Removes a set of unnecessary directories 2 | #execution mode: Combined 3 | #tags: Cleanup 4 | 5 | # Remove paths that we should not need to leave around in the image 6 | # Remove paths that we should not need to leave around in the image 7 | Remove-Item -Path "$Env:SystemDrive\Apps" -Recurse -Force -ErrorAction "SilentlyContinue" 8 | Remove-Item -Path "$Env:SystemDrive\DeployAgent" -Recurse -Force -ErrorAction "SilentlyContinue" 9 | Remove-Item -Path "$Env:SystemDrive\Users\AgentInstall.txt" -Force -Confirm:$false -ErrorAction "SilentlyContinue" 10 | Remove-Item -Path "$Env:SystemDrive\Users\AgentBootLoaderInstall.txt" -Force -Confirm:$false -ErrorAction "SilentlyContinue" 11 | Remove-Item -Path "$Env:Public\Desktop\*.lnk" -Force -Confirm:$false -ErrorAction "SilentlyContinue" 12 | -------------------------------------------------------------------------------- /apps/appv/Install-JGraphDrawIO.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Modules Evergreen 2 | [System.String] $Path = "$Env:SystemDrive\Temp" 3 | 4 | Import-Module -Name "Evergreen" -Force 5 | $App = Get-EvergreenApp -Name "JGraphDrawIO" | Where-Object { $_.Type -eq "msi" } | Select-Object -First 1 6 | $OutFile = Save-EvergreenApp -InputObject $App -CustomPath $Path -ErrorAction "Stop" 7 | 8 | $params = @{ 9 | FilePath = "$Env:SystemRoot\System32\msiexec.exe" 10 | ArgumentList = "/package `"$($OutFile.FullName)`" ALLUSERS=1 /quiet" 11 | NoNewWindow = $true 12 | Wait = $true 13 | PassThru = $true 14 | ErrorAction = "Stop" 15 | } 16 | Start-Process @params 17 | 18 | Start-Sleep -Seconds 5 19 | $Shortcuts = @("$Env:Public\Desktop\draw.io.lnk") 20 | Remove-Item -Path $Shortcuts -Force -ErrorAction "Ignore" 21 | #endregion 22 | -------------------------------------------------------------------------------- /variables/locale.json: -------------------------------------------------------------------------------- 1 | { 2 | "australiaeast": { 3 | "Language": "en-AU", 4 | "TimeZone": "AUS Eastern Standard Time" 5 | }, 6 | "australiasoutheast": { 7 | "Language": "en-AU", 8 | "TimeZone": "AUS Eastern Standard Time" 9 | }, 10 | "westus": { 11 | "Language": "en-US", 12 | "TimeZone": "Pacific Standard Time" 13 | }, 14 | "westus2": { 15 | "Language": "en-US", 16 | "TimeZone": "Pacific Standard Time" 17 | }, 18 | "eastus": { 19 | "Language": "en-US", 20 | "TimeZone": "Eastern Standard Time" 21 | }, 22 | "uksouth": { 23 | "Language": "en-GB", 24 | "TimeZone": "GMT Standard Time" 25 | }, 26 | "ukwest": { 27 | "Language": "en-GB", 28 | "TimeZone": "GMT Standard Time" 29 | } 30 | } -------------------------------------------------------------------------------- /shell-apps/Obsidian/Definition.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Obsidian", 3 | "description": "The free and flexible app for your private thoughts.", 4 | "isPublic": true, 5 | "publisher": "Obsidian", 6 | "detectScript": "#detectScript", 7 | "installScript": "#installScript", 8 | "uninstallScript": "#uninstallScript", 9 | "fileUnzip": false, 10 | "versions": [ 11 | { 12 | "name": "#version", 13 | "isPreview": false, 14 | "installScriptOverride": null, 15 | "file": { 16 | "sourceUrl": "#sourceUrl", 17 | "sha256": "#sha256" 18 | } 19 | } 20 | ], 21 | "source": { 22 | "import": true, 23 | "type": "Evergreen", 24 | "app": "Obsidian", 25 | "filter": "$_.Type -eq \"exe\"" 26 | } 27 | } -------------------------------------------------------------------------------- /nme/terraform/private-dns.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | pl_zones = { 3 | automation = "privatelink.azure-automation.net" 4 | keyvault = "privatelink.vaultcore.azure.net" 5 | sqlserver = "privatelink.database.windows.net" 6 | website = "privatelink.azurewebsites.net" 7 | } 8 | } 9 | 10 | resource "azurerm_private_dns_zone" "private_link" { 11 | for_each = local.pl_zones 12 | 13 | name = each.value 14 | resource_group_name = local.resource_group_name 15 | } 16 | 17 | resource "azurerm_private_dns_zone_virtual_network_link" "private_link" { 18 | for_each = azurerm_private_dns_zone.private_link 19 | 20 | name = azurerm_virtual_network.nerdio.name 21 | resource_group_name = local.resource_group_name 22 | private_dns_zone_name = each.value.name 23 | virtual_network_id = azurerm_virtual_network.nerdio.id 24 | } 25 | -------------------------------------------------------------------------------- /shell-apps/Audacity/Definition.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Audacity", 3 | "description": "Audacity is a free, open source, cross-platform audio software for multi-track recording and editing.", 4 | "isPublic": true, 5 | "publisher": "Microsoft", 6 | "detectScript": "#detectScript", 7 | "installScript": "#installScript", 8 | "uninstallScript": "#uninstallScript", 9 | "fileUnzip": false, 10 | "versions": [ 11 | { 12 | "name": "#version", 13 | "isPreview": false, 14 | "installScriptOverride": null, 15 | "file": { 16 | "sourceUrl": "#sourceUrl", 17 | "sha256": "#sha256" 18 | } 19 | } 20 | ], 21 | "source": { 22 | "import": true, 23 | "type": "Evergreen", 24 | "app": "Audacity", 25 | "filter": "$_.Architecture -eq \"x64\"" 26 | } 27 | } -------------------------------------------------------------------------------- /actions/tools/Uninstall-MicrosoftAzurePipelinesAgent.ps1: -------------------------------------------------------------------------------- 1 | #description: Uninstalls the Microsoft Azure Pipelines agent. 2 | #execution mode: Combined 3 | #tags: Evergreen, Testing, DevOps 4 | #Requires -Modules Evergreen 5 | [System.String] $Path = "$Env:SystemDrive\agents" 6 | 7 | #region Script logic 8 | Push-Location -Path $Path 9 | $params = @{ 10 | FilePath = "$Path\config.cmd" 11 | ArgumentList = "remove --unattended --auth pat --token `"$($SecureVars.DevOpsPat)`"" 12 | Wait = $true 13 | NoNewWindow = $true 14 | PassThru = $true 15 | ErrorAction = "Stop" 16 | } 17 | Start-Process @params 18 | 19 | # Remove the C:\agents directory and the local user account used by the agent service 20 | Remove-Item -Path $Path -Recurse -Force -ErrorAction "SilentlyContinue" 21 | Remove-LocalUser -Name $SecureVars.DevOpsUser -Confirm:$false -ErrorAction "SilentlyContinue" 22 | #endregion 23 | -------------------------------------------------------------------------------- /shell-apps/Foxit/PDFReader/Definition.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Foxit PDF Reader", 3 | "description": "Foxit PDF Reader is a free PDF viewer that allows you to view, print, and annotate PDF documents.", 4 | "isPublic": true, 5 | "publisher": "Foxit Software", 6 | "detectScript": "#detectScript", 7 | "installScript": "#installScript", 8 | "uninstallScript": "#uninstallScript", 9 | "fileUnzip": false, 10 | "versions": [ 11 | { 12 | "name": "#version", 13 | "isPreview": false, 14 | "installScriptOverride": null, 15 | "file": { 16 | "sourceUrl": "#sourceUrl", 17 | "sha256": "#sha256" 18 | } 19 | } 20 | ], 21 | "source": { 22 | "import": true, 23 | "type": "Evergreen", 24 | "app": "FoxitReader", 25 | "filter": "$_.Language -eq \"English\"" 26 | } 27 | } -------------------------------------------------------------------------------- /shell-apps/JGraph/draw.io/Definition.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "draw.io", 3 | "description": "Work offline on your diagrams and save locally using the draw.io Desktop app for Windows.", 4 | "isPublic": true, 5 | "publisher": "JGraph", 6 | "detectScript": "#detectScript", 7 | "installScript": "#installScript", 8 | "uninstallScript": "#uninstallScript", 9 | "fileUnzip": false, 10 | "versions": [ 11 | { 12 | "name": "#version", 13 | "isPreview": false, 14 | "installScriptOverride": null, 15 | "file": { 16 | "sourceUrl": "#sourceUrl", 17 | "sha256": "#sha256" 18 | } 19 | } 20 | ], 21 | "source": { 22 | "import": true, 23 | "type": "Evergreen", 24 | "app": "JGraphDrawIO", 25 | "filter": "$_.Architecture -eq \"x86\" -and $_.Type -eq \"msi\"" 26 | } 27 | } -------------------------------------------------------------------------------- /shell-apps/dotPDN/Paint.NET/Definition.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Paint.NET", 3 | "description": "Paint.NET is a free image and photo editing software for Windows.", 4 | "isPublic": true, 5 | "publisher": "dotPDN", 6 | "detectScript": "#detectScript", 7 | "installScript": "#installScript", 8 | "uninstallScript": "#uninstallScript", 9 | "fileUnzip": true, 10 | "versions": [ 11 | { 12 | "name": "#version", 13 | "isPreview": false, 14 | "installScriptOverride": null, 15 | "file": { 16 | "sourceUrl": "#sourceUrl", 17 | "sha256": "#sha256" 18 | } 19 | } 20 | ], 21 | "source": { 22 | "import": true, 23 | "type": "Evergreen", 24 | "app": "PaintDotNetOfflineInstaller", 25 | "filter": "$_.Architecture -eq \"x64\" -and $_.URI -match \"winmsi\"" 26 | } 27 | } -------------------------------------------------------------------------------- /shell-apps/stealthpuppy/defaults/Definition.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Windows Enterprise Defaults", 3 | "description": "Make Windows images enterprise ready with optimisations and better defaults.", 4 | "isPublic": true, 5 | "publisher": "stealthpuppy", 6 | "detectScript": "#detectScript", 7 | "installScript": "#installScript", 8 | "uninstallScript": "#uninstallScript", 9 | "fileUnzip": false, 10 | "versions": [ 11 | { 12 | "name": "#version", 13 | "isPreview": false, 14 | "installScriptOverride": null, 15 | "file": { 16 | "sourceUrl": "#sourceUrl", 17 | "sha256": "#sha256" 18 | } 19 | } 20 | ], 21 | "source": { 22 | "import": true, 23 | "type": "Evergreen", 24 | "app": "WindowsEnterpriseDefaults", 25 | "filter": "$_.Type -eq \"zip\"" 26 | } 27 | } -------------------------------------------------------------------------------- /shell-apps/Google/Chrome/Definition.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Chrome", 3 | "description": "The browser built by Google. Browse with the power of Google.", 4 | "isPublic": true, 5 | "publisher": "Microsoft", 6 | "detectScript": "#detectScript", 7 | "installScript": "#installScript", 8 | "uninstallScript": "#uninstallScript", 9 | "fileUnzip": false, 10 | "versions": [ 11 | { 12 | "name": "#version", 13 | "isPreview": false, 14 | "installScriptOverride": null, 15 | "file": { 16 | "sourceUrl": "#sourceUrl", 17 | "sha256": "#sha256" 18 | } 19 | } 20 | ], 21 | "source": { 22 | "import": true, 23 | "type": "Evergreen", 24 | "app": "GoogleChrome", 25 | "filter": "$_.Channel -eq \"Stable\" -and $_.Architecture -eq \"x64\" -and $_.Type -eq \"msi\"" 26 | } 27 | } -------------------------------------------------------------------------------- /shell-apps/Microsoft/WindowsApp/Definition.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Windows App", 3 | "description": "Securely connect to Windows across Windows 365, Azure Virtual Desktop, Microsoft Dev Box, and more.", 4 | "isPublic": true, 5 | "publisher": "Microsoft", 6 | "detectScript": "#detectScript", 7 | "installScript": "#installScript", 8 | "uninstallScript": "#uninstallScript", 9 | "fileUnzip": false, 10 | "versions": [ 11 | { 12 | "name": "#version", 13 | "isPreview": false, 14 | "installScriptOverride": null, 15 | "file": { 16 | "sourceUrl": "#sourceUrl", 17 | "sha256": "#sha256" 18 | } 19 | } 20 | ], 21 | "source": { 22 | "import": true, 23 | "type": "Evergreen", 24 | "app": "MicrosoftWindowsApp", 25 | "filter": "$_.Architecture -eq \"x64\"" 26 | } 27 | } -------------------------------------------------------------------------------- /shell-apps/Microsoft/AzureCLI/Definition.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Azure CLI", 3 | "description": "Azure CLI is a cross-platform command-line tool for managing Azure resources with interactive commands or scripts.", 4 | "isPublic": true, 5 | "publisher": "Microsoft", 6 | "detectScript": "#detectScript", 7 | "installScript": "#installScript", 8 | "uninstallScript": "#uninstallScript", 9 | "fileUnzip": false, 10 | "versions": [ 11 | { 12 | "name": "#version", 13 | "isPreview": false, 14 | "installScriptOverride": null, 15 | "file": { 16 | "sourceUrl": "#sourceUrl", 17 | "sha256": "#sha256" 18 | } 19 | } 20 | ], 21 | "source": { 22 | "import": true, 23 | "type": "Evergreen", 24 | "app": "MicrosoftAzureCLI", 25 | "filter": "$_.Architecture -eq \"x64\"" 26 | } 27 | } -------------------------------------------------------------------------------- /shell-apps/Microsoft/VisualC++2022x64/Definition.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Visual C++ Redistributable 14 x64", 3 | "description": "The Visual C++ Redistributable installs runtime components that are required to run applications developed with Visual C++.", 4 | "isPublic": true, 5 | "publisher": "Microsoft", 6 | "detectScript": "#detectScript", 7 | "installScript": "#installScript", 8 | "uninstallScript": "#uninstallScript", 9 | "fileUnzip": false, 10 | "versions": [ 11 | { 12 | "name": "#version", 13 | "isPreview": false, 14 | "installScriptOverride": null, 15 | "file": { 16 | "sourceUrl": "#sourceUrl", 17 | "sha256": "#sha256" 18 | } 19 | } 20 | ], 21 | "source": { 22 | "type": "VcRedist", 23 | "filter": "$_.Architecture -eq \"x64\" -and $_.Release -eq \"14\"" 24 | } 25 | } -------------------------------------------------------------------------------- /shell-apps/Microsoft/VisualC++2022x86/Definition.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Visual C++ Redistributable 14 x86", 3 | "description": "The Visual C++ Redistributable installs runtime components that are required to run applications developed with Visual C++.", 4 | "isPublic": true, 5 | "publisher": "Microsoft", 6 | "detectScript": "#detectScript", 7 | "installScript": "#installScript", 8 | "uninstallScript": "#uninstallScript", 9 | "fileUnzip": false, 10 | "versions": [ 11 | { 12 | "name": "#version", 13 | "isPreview": false, 14 | "installScriptOverride": null, 15 | "file": { 16 | "sourceUrl": "#sourceUrl", 17 | "sha256": "#sha256" 18 | } 19 | } 20 | ], 21 | "source": { 22 | "type": "VcRedist", 23 | "filter": "$_.Architecture -eq \"x86\" -and $_.Release -eq \"14\"" 24 | } 25 | } -------------------------------------------------------------------------------- /shell-apps/Microsoft/AvdRtcService/Definition.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Remote Desktop WebRTC Redirector Service", 3 | "description": "The Remote Desktop WebRTC Redirector Service for Teams for Azure Virtual Desktop.", 4 | "isPublic": true, 5 | "publisher": "Microsoft", 6 | "detectScript": "#detectScript", 7 | "installScript": "#installScript", 8 | "uninstallScript": "#uninstallScript", 9 | "fileUnzip": false, 10 | "versions": [ 11 | { 12 | "name": "#version", 13 | "isPreview": false, 14 | "installScriptOverride": null, 15 | "file": { 16 | "sourceUrl": "#sourceUrl", 17 | "sha256": "#sha256" 18 | } 19 | } 20 | ], 21 | "source": { 22 | "import": true, 23 | "type": "Evergreen", 24 | "app": "MicrosoftWvdRtcService", 25 | "filter": "$_.Architecture -eq \"x64\"" 26 | } 27 | } -------------------------------------------------------------------------------- /shell-apps/Microsoft/Edge/Definition.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Edge", 3 | "description": "Microsoft Edge is a cross-platform web browser developed by Microsoft, based on the Chromium open-source project.", 4 | "isPublic": true, 5 | "publisher": "Microsoft", 6 | "detectScript": "#detectScript", 7 | "installScript": "#installScript", 8 | "uninstallScript": "#uninstallScript", 9 | "fileUnzip": false, 10 | "versions": [ 11 | { 12 | "name": "#version", 13 | "isPreview": false, 14 | "installScriptOverride": null, 15 | "file": { 16 | "sourceUrl": "#sourceUrl", 17 | "sha256": "#sha256" 18 | } 19 | } 20 | ], 21 | "source": { 22 | "import": true, 23 | "type": "Evergreen", 24 | "app": "MicrosoftEdge", 25 | "filter": "$_.Channel -eq \"Stable\" -and $_.Architecture -eq \"x64\"" 26 | } 27 | } -------------------------------------------------------------------------------- /shell-apps/Microsoft/Teams/Definition.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Teams", 3 | "description": "Microsoft Teams is a collaboration app that helps your team stay organized and has conversations all in one place.", 4 | "isPublic": true, 5 | "publisher": "Microsoft", 6 | "detectScript": "#detectScript", 7 | "installScript": "#installScript", 8 | "uninstallScript": "#uninstallScript", 9 | "fileUnzip": false, 10 | "versions": [ 11 | { 12 | "name": "#version", 13 | "isPreview": false, 14 | "installScriptOverride": null, 15 | "file": { 16 | "sourceUrl": "#sourceUrl", 17 | "sha256": "#sha256" 18 | } 19 | } 20 | ], 21 | "source": { 22 | "import": true, 23 | "type": "Evergreen", 24 | "app": "MicrosoftTeams", 25 | "filter": "$_.Architecture -eq \"x64\" -and $_.Release -eq \"Enterprise\"" 26 | } 27 | } -------------------------------------------------------------------------------- /shell-apps/Adobe/AcrobatReader/Definition.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Acrobat Reader DC", 3 | "description": "Adobe Acrobat Reader DC is a free PDF viewer that allows you to view, print, and annotate PDF documents.", 4 | "isPublic": true, 5 | "publisher": "Adobe", 6 | "detectScript": "#detectScript", 7 | "installScript": "#installScript", 8 | "uninstallScript": "#uninstallScript", 9 | "fileUnzip": false, 10 | "versions": [ 11 | { 12 | "name": "#version", 13 | "isPreview": false, 14 | "installScriptOverride": null, 15 | "file": { 16 | "sourceUrl": "#sourceUrl", 17 | "sha256": "#sha256" 18 | } 19 | } 20 | ], 21 | "source": { 22 | "import": true, 23 | "type": "Evergreen", 24 | "app": "AdobeAcrobatReaderDC", 25 | "filter": "$_.Architecture -eq \"x64\" -and $_.Language -eq \"MUI\"" 26 | } 27 | } -------------------------------------------------------------------------------- /shell-apps/Microsoft/OneDrive/Definition.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "OneDrive", 3 | "description": "OneDrive is a file hosting service that allows users to store files and data in the cloud.", 4 | "isPublic": true, 5 | "publisher": "Microsoft", 6 | "detectScript": "#detectScript", 7 | "installScript": "#installScript", 8 | "uninstallScript": "#uninstallScript", 9 | "fileUnzip": false, 10 | "versions": [ 11 | { 12 | "name": "#version", 13 | "isPreview": false, 14 | "installScriptOverride": null, 15 | "file": { 16 | "sourceUrl": "#sourceUrl", 17 | "sha256": "#sha256" 18 | } 19 | } 20 | ], 21 | "source": { 22 | "import": true, 23 | "type": "Evergreen", 24 | "app": "MicrosoftOneDrive", 25 | "filter": "$_.Ring -eq \"Production\" -and $_.Architecture -eq \"x64\" -and $_.Throttle -eq \"100\"" 26 | } 27 | } -------------------------------------------------------------------------------- /shell-apps/Zoom/Workplace/Definition.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Zoom Workplace", 3 | "description": "Zoom Workplace is a collaboration platform that brings together chat, video, and file sharing in one place.", 4 | "isPublic": true, 5 | "publisher": "Zoom", 6 | "detectScript": "#detectScript", 7 | "installScript": "#installScript", 8 | "uninstallScript": "#uninstallScript", 9 | "fileUnzip": false, 10 | "versions": [ 11 | { 12 | "name": "#version", 13 | "isPreview": false, 14 | "installScriptOverride": null, 15 | "file": { 16 | "sourceUrl": "#sourceUrl", 17 | "sha256": "#sha256" 18 | } 19 | } 20 | ], 21 | "source": { 22 | "import": true, 23 | "type": "Evergreen", 24 | "app": "Zoom", 25 | "filter": "$_.Architecture -eq \"x64\" -and $_.Type -eq \"msi\" -and $_.Platform -eq \"Desktop\"" 26 | } 27 | } -------------------------------------------------------------------------------- /shell-apps/ImageGlass/Definition.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ImageGlass", 3 | "description": "ImageGlass is a lightweight, versatile image viewer that supports a wide range of image formats and provides a user-friendly interface for viewing and managing images.", 4 | "isPublic": true, 5 | "publisher": "Duong Dieu Phap", 6 | "detectScript": "#detectScript", 7 | "installScript": "#installScript", 8 | "uninstallScript": "#uninstallScript", 9 | "fileUnzip": false, 10 | "versions": [ 11 | { 12 | "name": "#version", 13 | "isPreview": false, 14 | "installScriptOverride": null, 15 | "file": { 16 | "sourceUrl": "#sourceUrl", 17 | "sha256": "#sha256" 18 | } 19 | } 20 | ], 21 | "source": { 22 | "import": true, 23 | "type": "Evergreen", 24 | "app": "ImageGlass", 25 | "filter": "$_.Architecture -eq \"x64\"" 26 | } 27 | } -------------------------------------------------------------------------------- /shell-apps/Microsoft/AptosFont/Definition.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Aptos Font", 3 | "description": "Microsoft Aptos fonts for local installation for use in applications that do not have access to the Office Font Service.", 4 | "isPublic": true, 5 | "publisher": "Microsoft", 6 | "detectScript": "#detectScript", 7 | "installScript": "#installScript", 8 | "uninstallScript": "#uninstallScript", 9 | "fileUnzip": true, 10 | "versions": [ 11 | { 12 | "name": "#version", 13 | "isPreview": false, 14 | "installScriptOverride": null, 15 | "file": { 16 | "sourceUrl": "#sourceUrl", 17 | "sha256": "#sha256" 18 | } 19 | } 20 | ], 21 | "source": { 22 | "type": "Static", 23 | "version": "4.40", 24 | "url": "https://stavddsplbxulhzmac.blob.core.windows.net/binaries/MicrosoftAptosFonts.zip", 25 | "path": null 26 | } 27 | } -------------------------------------------------------------------------------- /shell-apps/Microsoft/PowerToys/Definition.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "PowerToys", 3 | "description": "PowerToys is a set of utilities for power users to tune and streamline their Windows experience for greater productivity.", 4 | "isPublic": true, 5 | "publisher": "Microsoft", 6 | "detectScript": "#detectScript", 7 | "installScript": "#installScript", 8 | "uninstallScript": "#uninstallScript", 9 | "fileUnzip": false, 10 | "versions": [ 11 | { 12 | "name": "#version", 13 | "isPreview": false, 14 | "installScriptOverride": null, 15 | "file": { 16 | "sourceUrl": "#sourceUrl", 17 | "sha256": "#sha256" 18 | } 19 | } 20 | ], 21 | "source": { 22 | "import": true, 23 | "type": "Evergreen", 24 | "app": "MicrosoftPowerToys", 25 | "filter": "$_.Architecture -eq \"x64\" -and $_.InstallerType -eq \"Default\"" 26 | } 27 | } -------------------------------------------------------------------------------- /shell-apps/Microsoft/SQLServerManagementStudio/Definition.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "SQL Server Management Studio", 3 | "description": "SQL Server Management Studio (SSMS) is an integrated environment for managing any SQL infrastructure, from SQL Server to Azure SQL Database.", 4 | "isPublic": true, 5 | "publisher": "Microsoft", 6 | "detectScript": "#detectScript", 7 | "installScript": "#installScript", 8 | "uninstallScript": "#uninstallScript", 9 | "fileUnzip": false, 10 | "versions": [ 11 | { 12 | "name": "#version", 13 | "isPreview": false, 14 | "installScriptOverride": null, 15 | "file": { 16 | "sourceUrl": "#sourceUrl", 17 | "sha256": "#sha256" 18 | } 19 | } 20 | ], 21 | "source": { 22 | "import": true, 23 | "type": "Evergreen", 24 | "app": "MicrosoftSsms", 25 | "filter": "$_.Language -eq \"English\"" 26 | } 27 | } -------------------------------------------------------------------------------- /actions/tweaks/Install-FSLogixAppMaskingRuleset.ps1: -------------------------------------------------------------------------------- 1 | #description: Downloads and installs an FSLogix App Masking ruleset 2 | #execution mode: Combined 3 | #tags: FSLogix 4 | [System.String] $Path = "$Env:ProgramFiles\FSLogix\Apps\Rules" 5 | 6 | #region Script logic 7 | New-Item -Path $Path -ItemType "Directory" -Force -ErrorAction "SilentlyContinue" | Out-Null 8 | New-Item -Path "$Env:SystemRoot\Logs\ImageBuild" -ItemType "Directory" -Force -ErrorAction "SilentlyContinue" | Out-Null 9 | 10 | $params = @{ 11 | Uri = $SecureVars.AppMaskingRuleset 12 | OutFile = "$Path\ruleset.zip" 13 | UseBasicParsing = $true 14 | ErrorAction = "Stop" 15 | } 16 | Invoke-WebRequest @params 17 | 18 | $params = @{ 19 | Path = "$Path\ruleset.zip" 20 | DestinationPath = $Path 21 | Force = $true 22 | ErrorAction = "Stop" 23 | } 24 | Expand-Archive @params 25 | 26 | Remove-Item -Path "$Path\ruleset.zip" -Force -ErrorAction "SilentlyContinue" 27 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/AvdMultimediaRedirection/Definition.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Multimedia Redirection Extensions", 3 | "description": "This extension enables multimedia redirection for Azure Virtual Desktop, allowing for enhanced media playback performance.", 4 | "isPublic": true, 5 | "publisher": "Microsoft", 6 | "detectScript": "#detectScript", 7 | "installScript": "#installScript", 8 | "uninstallScript": "#uninstallScript", 9 | "fileUnzip": false, 10 | "versions": [ 11 | { 12 | "name": "#version", 13 | "isPreview": false, 14 | "installScriptOverride": null, 15 | "file": { 16 | "sourceUrl": "#sourceUrl", 17 | "sha256": "#sha256" 18 | } 19 | } 20 | ], 21 | "source": { 22 | "import": true, 23 | "type": "Evergreen", 24 | "app": "MicrosoftWvdMultimediaRedirection", 25 | "filter": "$_.Architecture -eq \"x64\"" 26 | } 27 | } -------------------------------------------------------------------------------- /shell-apps/Microsoft/EdgeWebView2/Definition.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Edge WebView2", 3 | "description": "Microsoft Edge WebView2 is a control that allows you to embed web content in your applications using the Edge rendering engine.", 4 | "isPublic": true, 5 | "publisher": "Microsoft", 6 | "detectScript": "#detectScript", 7 | "installScript": "#installScript", 8 | "uninstallScript": "#uninstallScript", 9 | "fileUnzip": false, 10 | "versions": [ 11 | { 12 | "name": "#version", 13 | "isPreview": false, 14 | "installScriptOverride": null, 15 | "file": { 16 | "sourceUrl": "#sourceUrl", 17 | "sha256": "#sha256" 18 | } 19 | } 20 | ], 21 | "source": { 22 | "import": true, 23 | "type": "Evergreen", 24 | "app": "MicrosoftEdgeWebView2Runtime", 25 | "filter": "$_.Channel -eq \"Stable\" -and $_.Architecture -eq \"x64\"" 26 | } 27 | } -------------------------------------------------------------------------------- /shell-apps/Microsoft/SupportCenter/Definition.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Configuration Manager Support Center", 3 | "description": "Support Center has powerful capabilities including troubleshooting and real-time log viewing.", 4 | "isPublic": true, 5 | "publisher": "Microsoft", 6 | "detectScript": "#detectScript", 7 | "installScript": "#installScript", 8 | "uninstallScript": "#uninstallScript", 9 | "fileUnzip": false, 10 | "versions": [ 11 | { 12 | "name": "#version", 13 | "isPreview": false, 14 | "installScriptOverride": null, 15 | "file": { 16 | "sourceUrl": "#sourceUrl", 17 | "sha256": "#sha256" 18 | } 19 | } 20 | ], 21 | "source": { 22 | "type": "Static", 23 | "version": "5.2403.1209.1000", 24 | "url": "https://stavddsplbxulhzmac.blob.core.windows.net/binaries/SupportCenterInstaller.msi", 25 | "path": null 26 | } 27 | } -------------------------------------------------------------------------------- /shell-apps/Microsoft/NETLTS/Definition.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": ".NET LTS", 3 | "description": ".NET platform that receives support and updates for an extended period, ensuring stability and security for applications built on it.", 4 | "isPublic": true, 5 | "publisher": "Microsoft", 6 | "detectScript": "#detectScript", 7 | "installScript": "#installScript", 8 | "uninstallScript": "#uninstallScript", 9 | "fileUnzip": false, 10 | "versions": [ 11 | { 12 | "name": "#version", 13 | "isPreview": false, 14 | "installScriptOverride": null, 15 | "file": { 16 | "sourceUrl": "#sourceUrl", 17 | "sha256": "#sha256" 18 | } 19 | } 20 | ], 21 | "source": { 22 | "import": true, 23 | "type": "Evergreen", 24 | "app": "Microsoft.NET", 25 | "filter": "$_.Installer -eq \"windowsdesktop\" -and $_.Architecture -eq \"x64\" -and $_.Channel -match \"LTS\"" 26 | } 27 | } -------------------------------------------------------------------------------- /shell-apps/ImageGlass/Install.ps1: -------------------------------------------------------------------------------- 1 | $Context.Log("Installing package: $($Context.GetAttachedBinary())") 2 | $params = @{ 3 | FilePath = "$Env:SystemRoot\System32\msiexec.exe" 4 | ArgumentList = "/package `"$($Context.GetAttachedBinary())`" RUNAPPLICATION=0 ALLUSERS=1 ALLUSERS=1 /quiet" 5 | Wait = $true 6 | PassThru = $true 7 | NoNewWindow = $true 8 | ErrorAction = "Stop" 9 | } 10 | $result = Start-Process @params 11 | $Context.Log("Install complete. Return code: $($result.ExitCode)") 12 | 13 | Start-Sleep -Seconds 5 14 | $Shortcuts = @("$Env:Public\Desktop\ImageGlass.lnk", 15 | "$Env:ProgramData\Microsoft\Windows\Start Menu\Programs\ImageGlass\ImageGlass' LICENSE.lnk", 16 | "$Env:ProgramData\Microsoft\Windows\Start Menu\Programs\ImageGlass\Uninstall ImageGlass*.lnk") 17 | Get-Item -Path $Shortcuts -ErrorAction "SilentlyContinue" | ` 18 | ForEach-Object { $Context.Log("Remove file: $($_.FullName)"); Remove-Item -Path $_.FullName -Force -ErrorAction "SilentlyContinue" } 19 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/NETLTS/Detect.ps1: -------------------------------------------------------------------------------- 1 | # Variables 2 | [System.String] $FilePath = "${Env:ProgramFiles}\dotnet\host\fxr\$($Context.TargetVersion)\hostfxr.dll" 3 | 4 | # Detection logic 5 | if ([System.String]::IsNullOrEmpty($Context.TargetVersion)) { 6 | # This should be an uninstall action 7 | if (Test-Path -Path $FilePath) { return $true } 8 | else { 9 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 10 | } 11 | } 12 | else { 13 | if (Test-Path -Path $FilePath) { 14 | # Version on the file won't match the version of the .NET runtime, so we need to check the file's existence only. 15 | $Context.Log("File exists at: $($FilePath)") 16 | if ($Context.Versions -is [System.Array]) { return $Context.TargetVersion } else { return $true } 17 | } 18 | else { 19 | $Context.Log("File does not exist at: $($FilePath)") 20 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/FSLogixApps/Definition.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "FSLogix Apps", 3 | "description": "FSLogix Apps is a set of solutions that enhance the user experience in virtual desktop environments by providing advanced profile management, application masking, and Office 365 containerization.", 4 | "isPublic": true, 5 | "publisher": "Microsoft", 6 | "detectScript": "#detectScript", 7 | "installScript": "#installScript", 8 | "uninstallScript": "#uninstallScript", 9 | "fileUnzip": false, 10 | "versions": [ 11 | { 12 | "name": "#version", 13 | "isPreview": false, 14 | "installScriptOverride": null, 15 | "file": { 16 | "sourceUrl": "#sourceUrl", 17 | "sha256": "#sha256" 18 | } 19 | } 20 | ], 21 | "source": { 22 | "import": true, 23 | "type": "Evergreen", 24 | "app": "MicrosoftFSLogixApps", 25 | "filter": "$_.Channel -eq \"Production\"" 26 | } 27 | } -------------------------------------------------------------------------------- /shell-apps/Microsoft/PowerShell/Definition.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "PowerShell LTS", 3 | "description": "PowerShell is a cross-platform task automation solution made up of a command-line shell, a scripting language, and a configuration management framework.", 4 | "isPublic": true, 5 | "publisher": "Microsoft", 6 | "detectScript": "#detectScript", 7 | "installScript": "#installScript", 8 | "uninstallScript": "#uninstallScript", 9 | "fileUnzip": false, 10 | "versions": [ 11 | { 12 | "name": "#version", 13 | "isPreview": false, 14 | "installScriptOverride": null, 15 | "file": { 16 | "sourceUrl": "#sourceUrl", 17 | "sha256": "#sha256" 18 | } 19 | } 20 | ], 21 | "source": { 22 | "import": true, 23 | "type": "Evergreen", 24 | "app": "MicrosoftPowerShell", 25 | "filter": "$_.Architecture -eq \"x64\" -and $_.Type -eq \"msi\" -and $_.Release -eq \"LTS\"" 26 | } 27 | } -------------------------------------------------------------------------------- /shell-apps/Microsoft/VisualStudioCode/Definition.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Visual Studio Code", 3 | "description": "Visual Studio Code is a code editor redefined and optimized for building and debugging modern web and cloud applications.", 4 | "isPublic": true, 5 | "publisher": "Microsoft", 6 | "detectScript": "#detectScript", 7 | "installScript": "#installScript", 8 | "uninstallScript": "#uninstallScript", 9 | "fileUnzip": false, 10 | "versions": [ 11 | { 12 | "name": "#version", 13 | "isPreview": false, 14 | "installScriptOverride": null, 15 | "file": { 16 | "sourceUrl": "#sourceUrl", 17 | "sha256": "#sha256" 18 | } 19 | } 20 | ], 21 | "source": { 22 | "import": true, 23 | "type": "Evergreen", 24 | "app": "MicrosoftVisualStudioCode", 25 | "filter": "$_.Architecture -eq \"x64\" -and $_.Channel -eq \"Stable\" -and $_.Platform -eq \"win32-x64\"" 26 | } 27 | } -------------------------------------------------------------------------------- /apps/appv/Install-ImageGlass.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Modules Evergreen 2 | [System.String] $Path = "$Env:SystemDrive\Temp" 3 | 4 | Import-Module -Name "Evergreen" -Force 5 | $App = Get-EvergreenApp -Name "ImageGlass" | Where-Object { $_.Architecture -eq "x64" -and $_.Type -eq "msi" } | Select-Object -First 1 6 | $OutFile = Save-EvergreenApp -InputObject $App -CustomPath $Path -ErrorAction "Stop" 7 | 8 | $params = @{ 9 | FilePath = "$Env:SystemRoot\System32\msiexec.exe" 10 | ArgumentList = "/package `"$($OutFile.FullName)`" RUNAPPLICATION=0 ALLUSERS=1 /quiet" 11 | NoNewWindow = $true 12 | Wait = $true 13 | PassThru = $true 14 | ErrorAction = "Stop" 15 | } 16 | Start-Process @params 17 | 18 | Start-Sleep -Seconds 5 19 | $Shortcuts = @("$Env:Public\Desktop\ImageGlass.lnk", 20 | "$Env:ProgramData\Microsoft\Windows\Start Menu\Programs\ImageGlass\ImageGlass' LICENSE.lnk", 21 | "$Env:ProgramData\Microsoft\Windows\Start Menu\Programs\ImageGlass\Uninstall ImageGlass*.lnk") 22 | Remove-Item -Path $Shortcuts -Force -ErrorAction "Ignore" 23 | #endregion 24 | -------------------------------------------------------------------------------- /shell-apps/Foxit/PDFReader/Install.ps1: -------------------------------------------------------------------------------- 1 | $Options = "AUTO_UPDATE=0 2 | NOTINSTALLUPDATE=1 3 | MAKEDEFAULT=0 4 | LAUNCHCHECKDEFAULT=0 5 | VIEW_IN_BROWSER=0 6 | DESKTOP_SHORTCUT=0 7 | STARTMENU_SHORTCUT_UNINSTALL=0 8 | DISABLE_UNINSTALL_SURVEY=1 9 | CLEAN=1 10 | INTERNET_DISABLE=1" 11 | $params = @{ 12 | FilePath = "$Env:SystemRoot\System32\msiexec.exe" 13 | ArgumentList = "/package `"$($Context.GetAttachedBinary())`" $($Options -replace "\s+", " ") ALLUSERS=1 /quiet" 14 | Wait = $true 15 | PassThru = $true 16 | NoNewWindow = $true 17 | ErrorAction = "Stop" 18 | } 19 | $result = Start-Process @params 20 | $Context.Log("Install complete. Return code: $($result.ExitCode)") 21 | 22 | # Disable update tasks - assuming we're installing on a gold image or updates will be managed 23 | $Context.Log("Disable service: FoxitReaderUpdateService*") 24 | Get-Service -Name "FoxitReaderUpdateService*" -ErrorAction "SilentlyContinue" | Set-Service -StartupType "Disabled" -ErrorAction "SilentlyContinue" 25 | -------------------------------------------------------------------------------- /apps/appv/Install-NotepadPlusPlus.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Modules Evergreen 2 | [System.String] $Path = "$Env:SystemDrive\Temp" 3 | 4 | Import-Module -Name "Evergreen" -Force 5 | $App = Get-EvergreenApp -Name "NotepadPlusPlus" | Where-Object { $_.Architecture -eq "x64" -and $_.Type -eq "exe" } | Select-Object -First 1 6 | $OutFile = Save-EvergreenApp -InputObject $App -CustomPath $Path -ErrorAction "Stop" 7 | 8 | $params = @{ 9 | FilePath = $OutFile.FullName 10 | ArgumentList = "/S" 11 | NoNewWindow = $true 12 | Wait = $true 13 | PassThru = $true 14 | ErrorAction = "Stop" 15 | } 16 | Start-Process @params 17 | 18 | # Disable updater 19 | $UpdaterPath = "$Env:ProgramFiles\Notepad++\updater" 20 | $RenamePath = "$Env:ProgramFiles\Notepad++\updater.disabled" 21 | if (Test-Path -Path $UpdaterPath) { 22 | if (Test-Path -Path $RenamePath) { 23 | Remove-Item -Path $RenamePath -Recurse -Force -ErrorAction "SilentlyContinue" 24 | } 25 | Rename-Item -Path $UpdaterPath -NewName "updater.disabled" -Force -ErrorAction "SilentlyContinue" 26 | } 27 | #endregion 28 | -------------------------------------------------------------------------------- /actions/tools/Set-FSLogixStorageAccount.ps1: -------------------------------------------------------------------------------- 1 | #description: Configures authentication to an Azure storage account for FSLogix profiles, for Entra ID only environments 2 | #execution mode: Combined 3 | #tags: FSLogix, Storage Account 4 | 5 | #region Use Secure variables in Nerdio Manager to pass credentials 6 | if ($null -eq $SecureVars.HostPoolStorageAuth) { 7 | throw "Host pool storage auth not specified" 8 | } 9 | #endregion 10 | 11 | #region Configure access to the FSLogix storage account 12 | try { 13 | # Gather details from JSON file 14 | $Json = $SecureVars.HostPoolStorageAuth | ConvertFrom-Json -ErrorAction "Stop" 15 | 16 | # Store credentials to access the storage account 17 | & "$Env:SystemRoot\System32\cmdkey.exe" /add:$($Json.$HostPoolName.FileServer) /user:$($Json.$HostPoolName.User) /pass:$($Json.$HostPoolName.Secret) 18 | 19 | # Disable Windows Defender Credential Guard (required for Windows 11 22H2) 20 | reg add "HKLM\SYSTEM\CurrentControlSet\Control\Lsa" /v "LsaCfgFlags" /d 0 /t "REG_DWORD" /f | Out-Null 21 | } 22 | catch { 23 | throw $_ 24 | } 25 | #endregion 26 | -------------------------------------------------------------------------------- /nme/terraform/data.tf: -------------------------------------------------------------------------------- 1 | data "azuread_client_config" "current" {} 2 | data "azurerm_client_config" "current" {} 3 | data "azurerm_subscription" "current" {} 4 | data "azuread_application_published_app_ids" "well_known" {} 5 | 6 | data "azuread_service_principal" "msgraph" { 7 | client_id = data.azuread_application_published_app_ids.well_known.result.MicrosoftGraph 8 | } 9 | 10 | #The below is meant to convert the user_principal onto a valid UUID 11 | data "azuread_user" "desktop_admins" { 12 | for_each = var.desktop_admins 13 | user_principal_name = each.value 14 | } 15 | 16 | data "azuread_user" "desktop_users" { 17 | for_each = var.desktop_users 18 | user_principal_name = each.value 19 | } 20 | 21 | data "azuread_user" "helpdesk_users" { 22 | for_each = var.helpdesk_users 23 | user_principal_name = each.value 24 | } 25 | 26 | data "azuread_user" "reviewers" { 27 | for_each = var.reviewers 28 | user_principal_name = each.value 29 | } 30 | 31 | data "azuread_user" "nerdio_admins" { 32 | for_each = var.nerdio_admins 33 | user_principal_name = each.value 34 | } 35 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/OneDrive/Install.ps1: -------------------------------------------------------------------------------- 1 | $Context.Log("Run: 'reg add HKLM\Software\Microsoft\OneDrive /v AllUsersInstall /t REG_DWORD /d 1 /reg:64 /f'") 2 | reg add "HKLM\Software\Microsoft\OneDrive" /v "AllUsersInstall" /t REG_DWORD /d 1 /reg:64 /f *> $null 3 | $params = @{ 4 | FilePath = $Context.GetAttachedBinary() 5 | ArgumentList = "/silent /allusers" 6 | Wait = $false 7 | PassThru = $true 8 | NoNewWindow = $true 9 | ErrorAction = "Stop" 10 | } 11 | $result = Start-Process @params 12 | do { 13 | $Context.Log("Waiting for OneDrive Setup to complete.") 14 | Start-Sleep -Seconds 5 15 | } while (Get-Process -Name "OneDriveSetup" -ErrorAction "SilentlyContinue") 16 | $Context.Log("OneDrive Setup completed.") 17 | $Context.Log("Wait a further 10 seconds for processes to complete") 18 | Start-Sleep -Seconds 10 19 | Get-Process -Name "OneDrive" -ErrorAction "SilentlyContinue" | ForEach-Object { 20 | $Context.Log("Stopped OneDrive process: $($_.Name)") 21 | Stop-Process -Name $_.Name -Force -ErrorAction "SilentlyContinue" 22 | } 23 | $Context.Log("Install complete. Return code: $($result.ExitCode)") 24 | -------------------------------------------------------------------------------- /apps/appv/Install-VLCMediaPlayer.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Modules Evergreen 2 | [System.String] $Path = "$Env:SystemDrive\Temp" 3 | 4 | Import-Module -Name "Evergreen" -Force 5 | $App = Get-EvergreenApp -Name "VideoLanVlcPlayer" | Where-Object { $_.Architecture -eq "x64" -and $_.Type -eq "MSI" } | Select-Object -First 1 6 | $OutFile = Save-EvergreenApp -InputObject $App -CustomPath $Path -ErrorAction "Stop" 7 | 8 | $params = @{ 9 | FilePath = "$Env:SystemRoot\System32\msiexec.exe" 10 | ArgumentList = "/package `"$($OutFile.FullName)`" ALLUSERS=1 /quiet" 11 | NoNewWindow = $true 12 | Wait = $true 13 | PassThru = $true 14 | ErrorAction = "Stop" 15 | } 16 | Start-Process @params 17 | 18 | Start-Sleep -Seconds 5 19 | $Shortcuts = @("$Env:ProgramData\Microsoft\Windows\Start Menu\Programs\VideoLAN\VLC\VideoLAN website.lnk", 20 | "$Env:ProgramData\Microsoft\Windows\Start Menu\Programs\VideoLAN\VLC\Release Notes.lnk", 21 | "$Env:ProgramData\Microsoft\Windows\Start Menu\Programs\VideoLAN\VLC\Documentation.lnk", 22 | "$Env:Public\Desktop\VLC media player.lnk") 23 | Remove-Item -Path $Shortcuts -Force -ErrorAction "Ignore" 24 | -------------------------------------------------------------------------------- /actions/core/203_MicrosoftOutlook.ps1: -------------------------------------------------------------------------------- 1 | #description: Installs the new Microsoft Outlook app 2 | #execution mode: Combined 3 | #tags: Evergreen, Microsoft, Outlook, per-machine 4 | #Requires -Modules Evergreen 5 | [System.String] $Path = "$Env:SystemDrive\Apps\Microsoft\Outlook" 6 | New-Item -Path $Path -ItemType "Directory" -Force -ErrorAction "SilentlyContinue" | Out-Null 7 | 8 | # Import shared functions written to disk by 000_PrepImage.ps1 9 | $FunctionFile = "$Env:TEMP\NerdioFunctions.psm1" 10 | Import-Module -Name $FunctionFile -Force -ErrorAction "Stop" 11 | Write-LogFile -Message "Functions imported from: $FunctionFile" 12 | 13 | $App = [PSCustomObject]@{ 14 | Version = "2.0.0" 15 | URI = "https://res.cdn.office.net/nativehost/5mttl/installer/v2/indirect/Setup.exe" 16 | } 17 | $OutlookExe = Save-EvergreenApp -InputObject $App -CustomPath $Path -ErrorAction "Stop" 18 | Write-LogFile -Message "Downloaded Microsoft Outlook to: $($OutlookExe.FullName)" 19 | 20 | Write-LogFile -Message "Installing Microsoft Outlook" 21 | $params = @{ 22 | FilePath = $OutlookExe.FullName 23 | ArgumentList = "--provision true --quiet --start-" 24 | } 25 | Start-ProcessWithLog @params 26 | -------------------------------------------------------------------------------- /apps/appv/Install-Paint.NET.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Modules Evergreen 2 | [System.String] $Path = "$Env:SystemDrive\Temp" 3 | 4 | Import-Module -Name "Evergreen" -Force 5 | $App = Get-EvergreenApp -Name "PaintDotNetOfflineInstaller" | ` 6 | Where-Object { $_.Architecture -eq "x64" -and $_.URI -match "winmsi" } | Select-Object -First 1 7 | $OutFile = Save-EvergreenApp -InputObject $App -CustomPath $Path -ErrorAction "Stop" 8 | 9 | $params = @{ 10 | Path = $OutFile.FullName 11 | DestinationPath = $Path 12 | Force = $true 13 | ErrorAction = "Stop" 14 | } 15 | Expand-Archive @params 16 | 17 | $Installer = Get-ChildItem -Path $Path -Include "paint*.msi" -Recurse 18 | $params = @{ 19 | FilePath = "$Env:SystemRoot\System32\msiexec.exe" 20 | ArgumentList = "/package `"$($Installer.FullName)`" DESKTOPSHORTCUT=0 CHECKFORUPDATES=0 CHECKFORBETAS=0 /quiet" 21 | NoNewWindow = $true 22 | Wait = $true 23 | PassThru = $true 24 | ErrorAction = "Stop" 25 | } 26 | Start-Process @params 27 | 28 | Start-Sleep -Seconds 5 29 | $Shortcuts = @("$Env:Public\Desktop\Paint.NET.lnk") 30 | Remove-Item -Path $Shortcuts -Force -ErrorAction "Ignore" 31 | #endregion 32 | -------------------------------------------------------------------------------- /import/Detect.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "check32BitOn64System": false, 4 | "detectionType": "version", 5 | "detectionValue": "5.2203.1086.1000", 6 | "keyPath": "HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{69237C81-2AB9-4E98-B1AE-693DD9B070A8}", 7 | "operator": "greaterThanOrEqual", 8 | "valueName": "DisplayVersion" 9 | }, 10 | { 11 | "check32BitOn64System": false, 12 | "detectionType": "version", 13 | "detectionValue": "5.2203.1086.1000", 14 | "fileOrFolderName": "ConfigMgrSupportCenterViewer.exe", 15 | "operator": "greaterThanOrEqual", 16 | "path": "C:\\Program Files (x86)\\Configuration Manager Support Center" 17 | }, 18 | { 19 | "check32BitOn64System": false, 20 | "detectionType": "version", 21 | "detectionValue": "5.2203.1086.1000", 22 | "fileOrFolderName": "ConfigMgrSupportCenter.exe", 23 | "operator": "greaterThanOrEqual", 24 | "path": "C:\\Program Files (x86)\\Configuration Manager Support Center" 25 | }, 26 | { 27 | "productCode": "{69237C81-2AB9-4E98-B1AE-693DD9B070A8}", 28 | "productVersion": "5.2203.1086.1000", 29 | "productVersionOperator": "greaterThanOrEqual" 30 | } 31 | ] -------------------------------------------------------------------------------- /actions/tweaks/Set-AppLockerPolicyConfig.ps1: -------------------------------------------------------------------------------- 1 | #description: Downloads and installs a Microsoft AppLocker policy 2 | #execution mode: Combined 3 | #tags: AppLocker 4 | 5 | #region Script logic 6 | [System.String] $Path = "$Env:SystemDrive\Apps\AppLocker" 7 | New-Item -Path $Path -ItemType "Directory" -Force -ErrorAction "SilentlyContinue" | Out-Null 8 | 9 | if ([System.String]::IsNullOrEmpty($SecureVars.AppLockerPolicyFile)) { 10 | Write-Host "AppLocker configuration file URL not set." 11 | } 12 | else { 13 | #Download the AppLocker configuration 14 | $OutFile = "$Path\AppLocker$(Get-Date -Format "yyyyMMdd").xml" 15 | $params = @{ 16 | URI = $SecureVars.AppLockerPolicyFile 17 | OutFile = $OutFile 18 | UseBasicParsing = $true 19 | ErrorAction = "Stop" 20 | } 21 | Invoke-WebRequest @params 22 | 23 | # Start the Application Identity service 24 | Start-Service -Name "AppIDSvc" -ErrorAction "SilentlyContinue" 25 | sc.exe config appidsvc start= auto 26 | 27 | # Import the AppLocker configuration 28 | $params = @{ 29 | XmlPolicy = $OutFile 30 | ErrorAction = "Stop" 31 | } 32 | Set-AppLockerPolicy @params 33 | } 34 | #endregion 35 | -------------------------------------------------------------------------------- /apps/appv/Install-FoxitPDFReader.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Modules Evergreen 2 | [System.String] $Path = "$Env:SystemDrive\Temp" 3 | [System.String] $Language = "English" 4 | 5 | Import-Module -Name "Evergreen" -Force 6 | $App = Get-EvergreenApp -Name "FoxitReader" | Where-Object { $_.Language -eq $Language } | Select-Object -First 1 7 | $OutFile = Save-EvergreenApp -InputObject $App -CustomPath $Path -ErrorAction "Stop" 8 | 9 | $Options = "AUTO_UPDATE=0 10 | NOTINSTALLUPDATE=1 11 | MAKEDEFAULT=0 12 | LAUNCHCHECKDEFAULT=0 13 | VIEW_IN_BROWSER=0 14 | DESKTOP_SHORTCUT=0 15 | STARTMENU_SHORTCUT_UNINSTALL=0 16 | DISABLE_UNINSTALL_SURVEY=1 17 | CLEAN=1 18 | INTERNET_DISABLE=1" 19 | $params = @{ 20 | FilePath = "$Env:SystemRoot\System32\msiexec.exe" 21 | ArgumentList = "/package `"$($OutFile.FullName)`" $($Options -replace "\s+", " ") ALLUSERS=1 /quiet" 22 | NoNewWindow = $true 23 | Wait = $true 24 | PassThru = $true 25 | ErrorAction = "Stop" 26 | } 27 | Start-Process @params 28 | 29 | # Disable update tasks - assuming we're installing on a gold image or updates will be managed 30 | Get-Service -Name "FoxitReaderUpdateService*" -ErrorAction "SilentlyContinue" | Set-Service -StartupType "Disabled" -ErrorAction "SilentlyContinue" 31 | #endregion 32 | -------------------------------------------------------------------------------- /.devops/pipelines/validate-apps.yml: -------------------------------------------------------------------------------- 1 | # Add steps that build, run tests, deploy, and more: 2 | # https://aka.ms/yaml 3 | 4 | # trigger: 5 | # branches: 6 | # include: [ main ] 7 | # paths: 8 | # include: [ "scripts/**.ps1" ] 9 | 10 | pool: 'Azure Virtual Desktop' 11 | 12 | steps: 13 | - powershell: | 14 | Import-Module -Name "Pester" -Force -ErrorAction "Stop" 15 | $Config = New-PesterConfiguration 16 | $Config.Run.Path = "$(build.sourcesDirectory)\tests\image" 17 | $Config.Run.PassThru = $true 18 | $Config.TestResult.Enabled = $true 19 | $Config.TestResult.OutputFormat = "NUnitXml" 20 | $Config.TestResult.OutputPath = "$(build.sourcesDirectory)\TestResults.xml" 21 | $Config.Output.Verbosity = "Detailed" 22 | Invoke-Pester -Configuration $Config 23 | name: test 24 | displayName: 'Validate installed apps' 25 | workingDirectory: $(build.sourcesDirectory) 26 | errorActionPreference: continue 27 | continueOnError: true 28 | 29 | - publish: "$(build.sourcesDirectory)\\TestResults.xml" 30 | artifact: TestResults 31 | continueOnError: true 32 | 33 | - task: PublishTestResults@2 34 | inputs: 35 | testResultsFormat: "NUnit" 36 | testResultsFiles: "$(build.sourcesDirectory)\\TestResults.xml" 37 | failTaskOnFailedTests: true 38 | testRunTitle: "Publish Pester results" 39 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/FSLogixApps/Install.ps1: -------------------------------------------------------------------------------- 1 | # Configure the environment 2 | $ErrorActionPreference = [System.Management.Automation.ActionPreference]::Stop 3 | $InformationPreference = [System.Management.Automation.ActionPreference]::Continue 4 | $ProgressPreference = [System.Management.Automation.ActionPreference]::SilentlyContinue 5 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072 6 | 7 | # Unzip the attached binary to the current directory 8 | Expand-Archive -Path $Context.GetAttachedBinary() -DestinationPath $PWD -Force 9 | 10 | # Install FSLogix Apps agent 11 | foreach ($File in "FSLogixAppsSetup.exe") { 12 | $Installers = Get-ChildItem -Path $PWD -Recurse -Include $File | Where-Object { $_.Directory -match "x64" } 13 | foreach ($Installer in $Installers) { 14 | $Context.Log("Installing Microsoft FSLogix Apps agent from: $($Installer.FullName)") 15 | $params = @{ 16 | FilePath = $Installer.FullName 17 | ArgumentList = "/install /quiet /norestart" 18 | Wait = $true 19 | NoNewWindow = $true 20 | PassThru = $true 21 | ErrorAction = "Stop" 22 | } 23 | $result = Start-Process @params 24 | $Context.Log("Install complete. Return code: $($result.ExitCode)") 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /apps/configs/Redirections.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | AppData\Local\CrashDumps 7 | 8 | AppData\Local\Microsoft\Terminal Server Client 9 | 10 | AppData\Local\Microsoft\Edge SxS\User Data\Default\Cache 11 | 12 | AppData\Roaming\Microsoft\Teams\media-stack 13 | 14 | AppData\Roaming\Microsoft\Teams\Service Worker 15 | 16 | AppData\Roaming\Microsoft\Teams\meeting-addin\Cache 17 | 18 | 19 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/Teams/Detect.ps1: -------------------------------------------------------------------------------- 1 | # Variables 2 | [System.String] $PackageFamilyName = "MSTeams_8wekyb3d8bbwe" 3 | 4 | $App = Get-AppxPackage -AllUsers | Where-Object { $_.PackageFamilyName -eq $PackageFamilyName } 5 | if ([System.String]::IsNullOrEmpty($Context.TargetVersion)) { 6 | # This should be an uninstall action 7 | if ($null -eq $App) { 8 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 9 | } 10 | else { 11 | return $true 12 | } 13 | } 14 | else { 15 | if ($null -eq $App) { 16 | $Context.Log("Microsoft Teams is not installed.") 17 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 18 | } 19 | else { 20 | $Context.Log("Found version: $($App.Version)") 21 | if ([System.Version]::Parse($App.Version) -ge [System.Version]::Parse($Context.TargetVersion)) { 22 | $Context.Log("No update required. Found '$($App.Version)' against '$($Context.TargetVersion)'.") 23 | if ($Context.Versions -is [System.Array]) { return $App.Version } else { return $true } 24 | } 25 | else { 26 | $Context.Log("Update required. Found '$($App.Version)' less than '$($Context.TargetVersion)'.") 27 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /variables/NerdioManagerVariables.json: -------------------------------------------------------------------------------- 1 | { 2 | "australiaeast": { 3 | "Language": "en-AU", 4 | "OSLanguage": "en-AU", 5 | "TimeZone": "AUS Eastern Standard Time", 6 | "AppxMode": "Block", 7 | "FSLogixAppMaskingRuleset": "https://stavdxwopw3ptwuo4o.blob.core.windows.net/configs/AppMaskingRuleset.zip", 8 | "FSLogixRedirections": "https://stavdxwopw3ptwuo4o.blob.core.windows.net/configs/Redirections.xml", 9 | "Microsoft365AppsChannel": "Current", 10 | "Microsoft365AppsConfig": "https://stavdxwopw3ptwuo4o.blob.core.windows.net/configs/Microsoft365Apps-Outlook-Shared.xml", 11 | "FoxitLanguage": "English", 12 | "FirefoxLanguage": "en-US", 13 | "FirefoxChannel": "LATEST_FIREFOX_VERSION", 14 | "CitrixWorkspaceStream": "Current", 15 | "CitrixOptimizer": "https://stavdxwopw3ptwuo4o.blob.core.windows.net/binaries/CitrixOptimizerTool.zip", 16 | "CitrixOptimizerTemplate": "https://stavdxwopw3ptwuo4o.blob.core.windows.net/configs/CitrixOptimizer-Windows11-Lite.xml", 17 | "AppLockerPolicyFile": "https://stavdxwopw3ptwuo4o.blob.core.windows.net/configs/AppLockerRules-20231114-0803-Enforce.xml", 18 | "GreenshotDefaultsIni": "https://stavdxwopw3ptwuo4o.blob.core.windows.net/configs/greenshot-defaults.ini", 19 | "AdobeAcrobatArchitecture": "x64", 20 | "AdobeAcrobatLanguage": "MUI" 21 | } 22 | } -------------------------------------------------------------------------------- /actions/3rdparty/405_pdfforgePDFCreator.ps1: -------------------------------------------------------------------------------- 1 | #description: Installs the latest PDFForge PDFCreator 2 | #execution mode: Combined 3 | #tags: Evergreen, PDFForge, PDFCreator, PDF 4 | #Requires -Modules Evergreen 5 | [System.String] $Path = "$Env:SystemDrive\Apps\PDFForge\PDFCreator" 6 | New-Item -Path $Path -ItemType "Directory" -Force -ErrorAction "SilentlyContinue" | Out-Null 7 | 8 | # Import shared functions written to disk by 000_PrepImage.ps1 9 | $FunctionFile = "$Env:TEMP\NerdioFunctions.psm1" 10 | Import-Module -Name $FunctionFile -Force -ErrorAction "Stop" 11 | Write-LogFile -Message "Functions imported from: $FunctionFile" 12 | 13 | Write-LogFile -Message "Query Evergreen for PDFForge PDFCreator" 14 | $App = Get-EvergreenApp -Name "PDFForgePDFCreator" | Select-Object -First 1 15 | Write-LogFile -Message "Downloading PDFForge PDFCreator version $($App.Version) to $Path" 16 | $OutFile = Save-EvergreenApp -InputObject $App -CustomPath $Path -ErrorAction "Stop" 17 | 18 | $params = @{ 19 | FilePath = $OutFile.FullName 20 | ArgumentList = "/VerySilent /Lang=en /NoIcons /COMPONENTS=None" 21 | } 22 | Start-ProcessWithLog @params 23 | 24 | Start-Sleep -Seconds 5 25 | $Shortcuts = @("$Env:Public\Desktop\PDF Architect 9.lnk", 26 | "$Env:Public\Desktop\PDFCreator.lnk", 27 | "$Env:ProgramFiles\PDFCreator\PDF Architect\architect-setup.exe") 28 | Remove-Item -Path $Shortcuts -Force -ErrorAction "Ignore" 29 | -------------------------------------------------------------------------------- /actions/tools/Install-Pester.ps1: -------------------------------------------------------------------------------- 1 | #description: Installs the Pester PowerShell module. 2 | #execution mode: Combined 3 | #tags: Pester, Testing, DevOps 4 | 5 | # Trust the PSGallery for modules 6 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072 7 | Install-PackageProvider -Name "NuGet" -MinimumVersion "2.8.5.208" 8 | Install-PackageProvider -Name "PowerShellGet" -MinimumVersion "2.2.5" 9 | if (Get-PSRepository | Where-Object { $_.Name -eq $Repository -and $_.InstallationPolicy -ne "Trusted" }) { 10 | Set-PSRepository -Name $Repository -InstallationPolicy "Trusted" 11 | } 12 | 13 | foreach ($module in "Pester") { 14 | $installedModule = Get-Module -Name $module -ListAvailable -ErrorAction "SilentlyContinue" | ` 15 | Sort-Object -Property @{ Expression = { [System.Version]$_.Version }; Descending = $true } -ErrorAction "SilentlyContinue" | ` 16 | Select-Object -First 1 17 | $publishedModule = Find-Module -Name $module -ErrorAction "SilentlyContinue" 18 | if (($null -eq $installedModule) -or ([System.Version]$publishedModule.Version -gt [System.Version]$installedModule.Version)) { 19 | $params = @{ 20 | Name = $module 21 | SkipPublisherCheck = $true 22 | Force = $true 23 | ErrorAction = "Stop" 24 | } 25 | Install-Module @params 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /apps/appv/Install-Greenshot.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Modules Evergreen 2 | [System.String] $Path = "$Env:SystemDrive\Temp" 3 | 4 | Import-Module -Name "Evergreen" -Force 5 | $App = Get-EvergreenApp -Name "Greenshot" | Where-Object { $_.Type -eq "exe" -and $_.InstallerType -eq "Default" } | Select-Object -First 1 6 | $OutFile = Save-EvergreenApp -InputObject $App -CustomPath $Path -ErrorAction "Stop" 7 | 8 | $params = @{ 9 | FilePath = $OutFile.FullName 10 | ArgumentList = "/SP- /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /TASKS= /FORCECLOSEAPPLICATIONS /LOGCLOSEAPPLICATIONS /NORESTARTAPPLICATIONS" 11 | NoNewWindow = $true 12 | Wait = $false 13 | PassThru = $true 14 | ErrorAction = "Stop" 15 | } 16 | Start-Process @params 17 | 18 | # Close Greenshot 19 | Start-Sleep -Seconds 20 20 | Get-Process -ErrorAction "SilentlyContinue" | ` 21 | Where-Object { $_.Path -like "$Env:ProgramFiles\Greenshot\*" } | ` 22 | Stop-Process -Force -ErrorAction "SilentlyContinue" 23 | 24 | # Remove unneeded shortcuts 25 | $Shortcuts = @("$Env:Public\Desktop\Greenshot.lnk", 26 | "$Env:ProgramData\Microsoft\Windows\Start Menu\Programs\Greenshot\License.txt.lnk", 27 | "$Env:ProgramData\Microsoft\Windows\Start Menu\Programs\Greenshot\Readme.txt.lnk", 28 | "$Env:ProgramData\Microsoft\Windows\Start Menu\Programs\Greenshot\Uninstall Greenshot.lnk") 29 | Remove-Item -Path $Shortcuts -Force -ErrorAction "Ignore" 30 | #endregion 31 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/WindowsApp/Detect.ps1: -------------------------------------------------------------------------------- 1 | # Variables 2 | [System.String] $PackageFamilyName = "MicrosoftCorporationII.Windows365_8wekyb3d8bbwe" 3 | 4 | # Detection logic 5 | $App = Get-AppxPackage -AllUsers | Where-Object { $_.PackageFamilyName -eq $PackageFamilyName } 6 | if ([System.String]::IsNullOrEmpty($Context.TargetVersion)) { 7 | # This should be an uninstall action 8 | if ($null -eq $App) { 9 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 10 | } 11 | else { 12 | return $true 13 | } 14 | } 15 | else { 16 | if ($null -eq $App) { 17 | $Context.Log("Microsoft Windows App is not installed.") 18 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 19 | } 20 | else { 21 | $Context.Log("Found version: $($App.Version)") 22 | if ([System.Version]::Parse($App.Version) -ge [System.Version]::Parse($Context.TargetVersion)) { 23 | $Context.Log("No update required. Found '$($App.Version)' against '$($Context.TargetVersion)'.") 24 | if ($Context.Versions -is [System.Array]) { return $App.Version } else { return $true } 25 | } 26 | else { 27 | $Context.Log("Update required. Found '$($App.Version)' less than '$($Context.TargetVersion)'.") 28 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /actions/tweaks/Enable-RDPShortpath.ps1: -------------------------------------------------------------------------------- 1 | #description: Enable RDP Shortpath for managed and public networks - reboot required. This configuration should preferably be implemented via GPO. 2 | #execution mode: Combined 3 | #tags: RDP Shortpath, Image 4 | <# 5 | This configuration should be implemented via GPO 6 | https://learn.microsoft.com/en-us/azure/virtual-desktop/configure-rdp-shortpath 7 | #> 8 | 9 | # Add registry keys 10 | reg add "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations" /v "fUseUdpPortRedirector" /t "REG_DWORD" /d 1 /f 11 | reg add "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations" /v "UdpPortNumber" /t "REG_DWORD" /d 3390 /f 12 | reg add "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations" /v "ICEControl" /t "REG_DWORD" /d 2 /f 13 | 14 | # Add windows firewall rule 15 | $params = @{ 16 | DisplayName = "Remote Desktop - RDP Shortpath (UDP-In)" 17 | Action = "Allow" 18 | Description = "Inbound rule for the Remote Desktop service to allow RDP traffic. [UDP 3390]" 19 | Group = "@FirewallAPI.dll,-28752" 20 | Name = "RemoteDesktop-UserMode-In-Shortpath-UDP" 21 | PolicyStore = "PersistentStore" 22 | Profile = "Domain", "Private" 23 | Service = "TermService" 24 | Protocol = "UDP" 25 | LocalPort = 3390 26 | Program = "$Env:SystemRoot\system32\svchost.exe" 27 | Enabled = "true" 28 | ErrorAction = "Continue" 29 | } 30 | New-NetFirewallRule @params 31 | -------------------------------------------------------------------------------- /shell-apps/stealthpuppy/defaults/Detect.ps1: -------------------------------------------------------------------------------- 1 | # Variables 2 | [System.String] $RegPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{f38de27b-799e-4c30-8a01-bfdedc622944}" 3 | [System.String] $Value = "DisplayVersion" 4 | 5 | # Detection logic 6 | if ([System.String]::IsNullOrEmpty($Context.TargetVersion)) { 7 | # This should be an uninstall action 8 | if (Test-Path -Path $RegPath) { return $true } 9 | else { 10 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 11 | } 12 | } 13 | else { 14 | if (Test-Path -Path $RegPath) { 15 | $Context.Log("Key found: $RegPath") 16 | $RegItem = Get-ItemProperty -Path $RegPath -ErrorAction "SilentlyContinue" 17 | if ([System.Version]::Parse($RegItem.$Value) -ge [System.Version]::Parse($Context.TargetVersion)) { 18 | $Context.Log("No update required. Found '$($RegItem.$Value)' against '$($Context.TargetVersion)'.") 19 | if ($Context.Versions -is [System.Array]) { return $RegItem.$Value } else { return $true } 20 | } 21 | else { 22 | $Context.Log("Update required. Found '$($RegItem.$Value)' less than '$($Context.TargetVersion)'.") 23 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 24 | } 25 | } 26 | else { 27 | $Context.Log("Path does not exist at: $($RegPath)") 28 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /shell-apps/Obsidian/Uninstall.ps1: -------------------------------------------------------------------------------- 1 | function Get-InstalledSoftware { 2 | $PropertyNames = "DisplayName", "DisplayVersion", "Publisher", "UninstallString", "PSPath", "WindowsInstaller", 3 | "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize", "SystemComponent" 4 | ("HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", 5 | "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*") | ` 6 | ForEach-Object { 7 | Get-ItemProperty -Path $_ -Name $PropertyNames -ErrorAction "SilentlyContinue" | ` 8 | . { process { if ($null -ne $_.DisplayName) { $_ } } } | ` 9 | Where-Object { $_.SystemComponent -ne 1 } | ` 10 | Select-Object -Property @{n = "Name"; e = { $_.DisplayName } }, @{n = "Version"; e = { $_.DisplayVersion } }, "Publisher", 11 | "UninstallString", @{n = "RegistryPath"; e = { $_.PSPath -replace "Microsoft.PowerShell.Core\\Registry::", "" } }, 12 | "PSChildName", "WindowsInstaller", "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize" | ` 13 | Sort-Object -Property "Name", "Publisher" 14 | } 15 | } 16 | 17 | $Context.Log("Uninstalling Obsidian)") 18 | $params = @{ 19 | FilePath = "${Env:ProgramFiles}\Obsidian\Uninstall Obsidian.exe" 20 | ArgumentList = "/allusers /S" 21 | Wait = $true 22 | PassThru = $true 23 | NoNewWindow = $true 24 | ErrorAction = "Stop" 25 | } 26 | $result = Start-Process @params 27 | $Context.Log("Uninstall complete. Return code: $($result.ExitCode)") 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Nerdio Manager scripts 2 | 3 | ## 🖥️ Scripted Actions 4 | 5 | PowerShell scripts for integration with [Scripted Actions in Nerdio Manager](https://nmehelp.getnerdio.com/hc/en-us/articles/26124327585421-Scripted-Actions-Overview). 6 | 7 | Note: this code is provided as-is, without warranty or support of any kind. 8 | 9 | These scripts can be added to your Nerdio Manager install by specifying the paths below to add individual directories: 10 | 11 | * `/actions/core` - scripts for building a Windows 10/11 pooled desktop (single session or multi-session). Can be used to build an image or run against already deployed session hosts 12 | * `/actions/3rdparty` - scripts for installing 3rd party applications 13 | * `/actions/tweaks` - scripts for implementing specific configurations and tweaks for gold images or session hosts 14 | * `/actions/optimise` - scripts to optimise the Windows image 15 | 16 | ## 🐚 Shell Apps 17 | 18 | A set of example scripts for installing applications via [Shell Apps](https://nmehelp.getnerdio.com/hc/en-us/articles/25499430784909-UAM-Shell-apps-overview-and-usage). Also see: [Automating Nerdio Manager Shell Apps, with Evergreen, Part 1](https://stealthpuppy.com/nerdio-shell-apps-p1/). 19 | 20 | ## 🛠️ Migrate 21 | 22 | A set of scripts for various functions - scripts include uninstall of third party virtual desktop agents to assist in the migration to Azure Virtual Desktop or Windows 365. 23 | 24 | ## 🧩 Apps/AppV 25 | 26 | A set of scripts for installing applications to capture via application virtualization tools such as App-V. 27 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/AzureCLI/Detect.ps1: -------------------------------------------------------------------------------- 1 | [System.String] $DisplayName = "Microsoft Azure CLI" 2 | 3 | function Get-InstalledSoftware { 4 | $PropertyNames = "DisplayName", "DisplayVersion", "Publisher", "UninstallString", "PSPath", "WindowsInstaller", 5 | "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize", "SystemComponent" 6 | ("HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", 7 | "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*") | ` 8 | ForEach-Object { 9 | Get-ItemProperty -Path $_ -Name $PropertyNames -ErrorAction "SilentlyContinue" | ` 10 | . { process { if ($null -ne $_.DisplayName) { $_ } } } | ` 11 | Where-Object { $_.SystemComponent -ne 1 } | ` 12 | Select-Object -Property @{n = "Name"; e = { $_.DisplayName } }, @{n = "Version"; e = { $_.DisplayVersion } }, "Publisher", 13 | "UninstallString", @{n = "RegistryPath"; e = { $_.PSPath -replace "Microsoft.PowerShell.Core\\Registry::", "" } }, 14 | "PSChildName", "WindowsInstaller", "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize" | ` 15 | Sort-Object -Property "Name", "Publisher" 16 | } 17 | } 18 | 19 | $App = Get-InstalledSoftware | Where-Object { $_.Name -match "$DisplayName*" } 20 | if ($App) { 21 | if ($Context.Versions -is [System.Array]) { return $_.Version } else { return $true } 22 | } 23 | else { 24 | $Context.Log("Application not installed: $DisplayName") 25 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 26 | } 27 | -------------------------------------------------------------------------------- /nme/terraform/role-assignments.tf: -------------------------------------------------------------------------------- 1 | resource "azuread_app_role_assignment" "desktop_admins" { 2 | for_each = data.azuread_user.desktop_admins 3 | principal_object_id = each.value.object_id 4 | resource_object_id = azuread_service_principal.nerdio_manager.object_id 5 | app_role_id = "ed0cdef0-4267-4470-bfff-5e0b6944f9e4" 6 | } 7 | 8 | resource "azuread_app_role_assignment" "desktop_users" { 9 | for_each = data.azuread_user.desktop_users 10 | principal_object_id = each.value.object_id 11 | resource_object_id = azuread_service_principal.nerdio_manager.object_id 12 | app_role_id = "e856de81-1e53-486a-8668-7d564866ae39" 13 | } 14 | 15 | resource "azuread_app_role_assignment" "help_desk" { 16 | for_each = data.azuread_user.helpdesk_users 17 | principal_object_id = each.value.object_id 18 | resource_object_id = azuread_service_principal.nerdio_manager.object_id 19 | app_role_id = "a94e83da-b314-4232-b8c8-94508c5ed533" 20 | } 21 | 22 | resource "azuread_app_role_assignment" "reviewers" { 23 | for_each = data.azuread_user.reviewers 24 | principal_object_id = each.value.object_id 25 | resource_object_id = azuread_service_principal.nerdio_manager.object_id 26 | app_role_id = "0a1b7425-f55a-44a6-9caa-b9a5cc9448da" 27 | } 28 | 29 | resource "azuread_app_role_assignment" "wvd_admin" { 30 | for_each = data.azuread_user.nerdio_admins 31 | principal_object_id = each.value.object_id 32 | resource_object_id = azuread_service_principal.nerdio_manager.object_id 33 | app_role_id = "d1c2ade8-98f8-45fd-aa4a-6d06b947c66f" 34 | } 35 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/EdgeWebView2/Detect.ps1: -------------------------------------------------------------------------------- 1 | # Variables 2 | [System.String] $FilePath = "${Env:ProgramFiles(x86)}\Microsoft\EdgeWebView\Application\$($Context.TargetVersion)\msedgewebview2.exe" 3 | 4 | # Detection logic 5 | if ([System.String]::IsNullOrEmpty($Context.TargetVersion)) { 6 | # This should be an uninstall action 7 | if (Test-Path -Path $FilePath) { return $true } 8 | else { 9 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 10 | } 11 | } 12 | else { 13 | if (Test-Path -Path $FilePath) { 14 | $FileItem = Get-ChildItem -Path $FilePath -ErrorAction "SilentlyContinue" 15 | $Context.Log("File found: $($FileItem.FullName)") 16 | $FileInfo = [Diagnostics.FileVersionInfo]::GetVersionInfo($FileItem.FullName) 17 | if ([System.Version]::Parse($FileInfo.ProductVersion) -ge [System.Version]::Parse($Context.TargetVersion)) { 18 | $Context.Log("No update required. Found '$($FileInfo.ProductVersion)' against '$($Context.TargetVersion)'.") 19 | if ($Context.Versions -is [System.Array]) { return $FileInfo.ProductVersion } else { return $true } 20 | } 21 | else { 22 | $Context.Log("Update required. Found '$($FileInfo.ProductVersion)' less than '$($Context.TargetVersion)'.") 23 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 24 | } 25 | } 26 | else { 27 | $Context.Log("File does not exist at: $($FilePath)") 28 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/AzureCLI/Uninstall.ps1: -------------------------------------------------------------------------------- 1 | [System.String] $Name = "Microsoft Azure CLI" 2 | 3 | function Get-InstalledSoftware { 4 | $PropertyNames = "DisplayName", "DisplayVersion", "Publisher", "UninstallString", "PSPath", "WindowsInstaller", 5 | "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize", "SystemComponent" 6 | ("HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", 7 | "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*") | ` 8 | ForEach-Object { 9 | Get-ItemProperty -Path $_ -Name $PropertyNames -ErrorAction "SilentlyContinue" | ` 10 | . { process { if ($null -ne $_.DisplayName) { $_ } } } | ` 11 | Where-Object { $_.SystemComponent -ne 1 } | ` 12 | Select-Object -Property @{n = "Name"; e = { $_.DisplayName } }, @{n = "Version"; e = { $_.DisplayVersion } }, "Publisher", 13 | "UninstallString", @{n = "RegistryPath"; e = { $_.PSPath -replace "Microsoft.PowerShell.Core\\Registry::", "" } }, 14 | "PSChildName", "WindowsInstaller", "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize" | ` 15 | Sort-Object -Property "Name", "Publisher" 16 | } 17 | } 18 | 19 | Get-InstalledSoftware | Where-Object { $_.Name -match "$Name*" } | ForEach-Object { 20 | $Context.Log("Uninstalling Windows Installer: $($_.PSChildName)") 21 | $params = @{ 22 | FilePath = "$Env:SystemRoot\System32\msiexec.exe" 23 | ArgumentList = "/uninstall `"$($_.PSChildName)`" /quiet /norestart" 24 | Wait = $true 25 | NoNewWindow = $true 26 | ErrorAction = "Stop" 27 | } 28 | Start-Process @params 29 | $Context.Log("Uninstall complete") 30 | } 31 | -------------------------------------------------------------------------------- /actions/core/100_MicrosoftVcRedists.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Installs the supported Microsoft Visual C++ Redistributables (2012, 2013, 2022). 4 | 5 | .DESCRIPTION 6 | This script installs the Microsoft Visual C++ Redistributables for the specified versions (2012, 2013, 2022). 7 | It creates a directory to store the redistributable files and then proceeds to install them silently. 8 | 9 | .PARAMETER Path 10 | Specifies the path where the redistributable files will be stored. The default path is "$Env:SystemDrive\Apps\Microsoft\VcRedist". 11 | 12 | .EXAMPLE 13 | .\100_MicrosoftVcRedists.ps1 -Path "C:\Redist" 14 | 15 | This example installs the Microsoft Visual C++ Redistributables in the "C:\Redist" directory. 16 | 17 | .NOTES 18 | - This script requires the "VcRedist" module to be installed. 19 | - The script must be run with administrative privileges. 20 | #> 21 | 22 | #description: Installs the supported Microsoft Visual C++ Redistributables 23 | #execution mode: Combined 24 | #tags: VcRedist, Microsoft 25 | #Requires -Modules VcRedist 26 | [System.String] $Path = "$Env:SystemDrive\Apps\Microsoft\VcRedist" 27 | New-Item -Path $Path -ItemType "Directory" -Force -ErrorAction "SilentlyContinue" | Out-Null 28 | 29 | # Import shared functions written to disk by 000_PrepImage.ps1 30 | $FunctionFile = "$Env:TEMP\NerdioFunctions.psm1" 31 | Import-Module -Name $FunctionFile -Force -ErrorAction "Stop" 32 | Write-LogFile -Message "Functions imported from: $FunctionFile" 33 | 34 | # Run tasks/install apps 35 | Write-LogFile -Message "Installing Microsoft Visual C++ Redistributables" 36 | Import-Module -Name "VcRedist" -Force 37 | Get-VcList | Save-VcRedist -Path $Path | Install-VcRedist -Silent | Out-Null 38 | -------------------------------------------------------------------------------- /shell-apps/Zoom/Workplace/Uninstall.ps1: -------------------------------------------------------------------------------- 1 | function Get-InstalledSoftware { 2 | $PropertyNames = "DisplayName", "DisplayVersion", "Publisher", "UninstallString", "PSPath", "WindowsInstaller", 3 | "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize", "SystemComponent" 4 | ("HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", 5 | "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*") | ` 6 | ForEach-Object { 7 | Get-ItemProperty -Path $_ -Name $PropertyNames -ErrorAction "SilentlyContinue" | ` 8 | . { process { if ($null -ne $_.DisplayName) { $_ } } } | ` 9 | Where-Object { $_.SystemComponent -ne 1 } | ` 10 | Select-Object -Property @{n = "Name"; e = { $_.DisplayName } }, @{n = "Version"; e = { $_.DisplayVersion } }, "Publisher", 11 | "UninstallString", @{n = "RegistryPath"; e = { $_.PSPath -replace "Microsoft.PowerShell.Core\\Registry::", "" } }, 12 | "PSChildName", "WindowsInstaller", "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize" | ` 13 | Sort-Object -Property "Name", "Publisher" 14 | } 15 | } 16 | 17 | Get-InstalledSoftware | Where-Object { $_.Name -match "Zoom*" } | ForEach-Object { 18 | $Context.Log("Uninstalling Windows Installer: $($_.PSChildName)") 19 | $params = @{ 20 | FilePath = "$Env:SystemRoot\System32\msiexec.exe" 21 | ArgumentList = "/uninstall `"$($_.PSChildName)`" /quiet /norestart" 22 | Wait = $true 23 | PassThru = $true 24 | NoNewWindow = $true 25 | ErrorAction = "Stop" 26 | } 27 | $result = Start-Process @params 28 | $Context.Log("Uninstall complete. Return code: $($result.ExitCode)") 29 | } 30 | -------------------------------------------------------------------------------- /shell-apps/ImageGlass/Uninstall.ps1: -------------------------------------------------------------------------------- 1 | function Get-InstalledSoftware { 2 | $PropertyNames = "DisplayName", "DisplayVersion", "Publisher", "UninstallString", "PSPath", "WindowsInstaller", 3 | "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize", "SystemComponent" 4 | ("HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", 5 | "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*") | ` 6 | ForEach-Object { 7 | Get-ItemProperty -Path $_ -Name $PropertyNames -ErrorAction "SilentlyContinue" | ` 8 | . { process { if ($null -ne $_.DisplayName) { $_ } } } | ` 9 | Where-Object { $_.SystemComponent -ne 1 } | ` 10 | Select-Object -Property @{n = "Name"; e = { $_.DisplayName } }, @{n = "Version"; e = { $_.DisplayVersion } }, "Publisher", 11 | "UninstallString", @{n = "RegistryPath"; e = { $_.PSPath -replace "Microsoft.PowerShell.Core\\Registry::", "" } }, 12 | "PSChildName", "WindowsInstaller", "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize" | ` 13 | Sort-Object -Property "Name", "Publisher" 14 | } 15 | } 16 | 17 | Get-InstalledSoftware | Where-Object { $_.Name -match "ImageGlass*" } | ForEach-Object { 18 | $Context.Log("Uninstalling Windows Installer: $($_.PSChildName)") 19 | $params = @{ 20 | FilePath = "$Env:SystemRoot\System32\msiexec.exe" 21 | ArgumentList = "/uninstall `"$($_.PSChildName)`" /quiet /norestart" 22 | Wait = $true 23 | PassThru = $true 24 | NoNewWindow = $true 25 | ErrorAction = "Stop" 26 | } 27 | $result = Start-Process @params 28 | $Context.Log("Uninstall complete. Return code: $($result.ExitCode)") 29 | } 30 | -------------------------------------------------------------------------------- /shell-apps/JGraph/draw.io/Uninstall.ps1: -------------------------------------------------------------------------------- 1 | function Get-InstalledSoftware { 2 | $PropertyNames = "DisplayName", "DisplayVersion", "Publisher", "UninstallString", "PSPath", "WindowsInstaller", 3 | "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize", "SystemComponent" 4 | ("HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", 5 | "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*") | ` 6 | ForEach-Object { 7 | Get-ItemProperty -Path $_ -Name $PropertyNames -ErrorAction "SilentlyContinue" | ` 8 | . { process { if ($null -ne $_.DisplayName) { $_ } } } | ` 9 | Where-Object { $_.SystemComponent -ne 1 } | ` 10 | Select-Object -Property @{n = "Name"; e = { $_.DisplayName } }, @{n = "Version"; e = { $_.DisplayVersion } }, "Publisher", 11 | "UninstallString", @{n = "RegistryPath"; e = { $_.PSPath -replace "Microsoft.PowerShell.Core\\Registry::", "" } }, 12 | "PSChildName", "WindowsInstaller", "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize" | ` 13 | Sort-Object -Property "Name", "Publisher" 14 | } 15 | } 16 | 17 | Get-InstalledSoftware | Where-Object { $_.Name -match "draw.io*" } | ForEach-Object { 18 | $Context.Log("Uninstalling Windows Installer: $($_.PSChildName)") 19 | $params = @{ 20 | FilePath = "$Env:SystemRoot\System32\msiexec.exe" 21 | ArgumentList = "/uninstall `"$($_.PSChildName)`" /quiet /norestart" 22 | Wait = $true 23 | PassThru = $true 24 | NoNewWindow = $true 25 | ErrorAction = "Stop" 26 | } 27 | $result = Start-Process @params 28 | $Context.Log("Uninstall complete. Return code: $($result.ExitCode)") 29 | } 30 | -------------------------------------------------------------------------------- /shell-apps/Google/Chrome/Uninstall.ps1: -------------------------------------------------------------------------------- 1 | function Get-InstalledSoftware { 2 | $PropertyNames = "DisplayName", "DisplayVersion", "Publisher", "UninstallString", "PSPath", "WindowsInstaller", 3 | "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize", "SystemComponent" 4 | ("HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", 5 | "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*") | ` 6 | ForEach-Object { 7 | Get-ItemProperty -Path $_ -Name $PropertyNames -ErrorAction "SilentlyContinue" | ` 8 | . { process { if ($null -ne $_.DisplayName) { $_ } } } | ` 9 | Where-Object { $_.SystemComponent -ne 1 } | ` 10 | Select-Object -Property @{n = "Name"; e = { $_.DisplayName } }, @{n = "Version"; e = { $_.DisplayVersion } }, "Publisher", 11 | "UninstallString", @{n = "RegistryPath"; e = { $_.PSPath -replace "Microsoft.PowerShell.Core\\Registry::", "" } }, 12 | "PSChildName", "WindowsInstaller", "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize" | ` 13 | Sort-Object -Property "Name", "Publisher" 14 | } 15 | } 16 | 17 | Get-InstalledSoftware | Where-Object { $_.Name -match "Google Chrome*" } | ForEach-Object { 18 | $Context.Log("Uninstalling Windows Installer: $($_.PSChildName)") 19 | $params = @{ 20 | FilePath = "$Env:SystemRoot\System32\msiexec.exe" 21 | ArgumentList = "/uninstall `"$($_.PSChildName)`" /quiet /norestart" 22 | Wait = $true 23 | PassThru = $true 24 | NoNewWindow = $true 25 | ErrorAction = "Stop" 26 | } 27 | $result = Start-Process @params 28 | $Context.Log("Uninstall complete. Return code: $($result.ExitCode)") 29 | } 30 | -------------------------------------------------------------------------------- /shell-apps/ImageGlass/Detect.ps1: -------------------------------------------------------------------------------- 1 | # Variables 2 | [System.String] $FilePath = "${Env:ProgramFiles}\ImageGlass\ImageGlass.exe" 3 | 4 | # Detection logic 5 | if ([System.String]::IsNullOrEmpty($Context.TargetVersion)) { 6 | # This should be an uninstall action 7 | if (Test-Path -Path $FilePath) { return $true } 8 | else { 9 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 10 | } 11 | } 12 | else { 13 | # This should be an install action, so we need to check the file version 14 | if (Test-Path -Path $FilePath) { 15 | $Context.Log("File found: $FilePath") 16 | $FileItem = Get-ChildItem -Path $FilePath -ErrorAction "SilentlyContinue" 17 | $FileInfo = [Diagnostics.FileVersionInfo]::GetVersionInfo($FileItem.FullName) 18 | $Context.Log("File product version: $($FileInfo.FileVersion)") 19 | $Context.Log("Target Shell App version: $($Context.TargetVersion)") 20 | if ([System.Version]::Parse($FileInfo.FileVersion) -ge [System.Version]::Parse($Context.TargetVersion)) { 21 | $Context.Log("No update required. Found '$($FileInfo.FileVersion)' against '$($Context.TargetVersion)'.") 22 | if ($Context.Versions -is [System.Array]) { return $FileInfo.FileVersion } else { return $true } 23 | } 24 | else { 25 | $Context.Log("Update required. Found '$($FileInfo.FileVersion)' less than '$($Context.TargetVersion)'.") 26 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 27 | } 28 | } 29 | else { 30 | $Context.Log("File does not exist at: $($FilePath)") 31 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /shell-apps/dotPDN/Paint.NET/Uninstall.ps1: -------------------------------------------------------------------------------- 1 | function Get-InstalledSoftware { 2 | $PropertyNames = "DisplayName", "DisplayVersion", "Publisher", "UninstallString", "PSPath", "WindowsInstaller", 3 | "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize", "SystemComponent" 4 | ("HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", 5 | "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*") | ` 6 | ForEach-Object { 7 | Get-ItemProperty -Path $_ -Name $PropertyNames -ErrorAction "SilentlyContinue" | ` 8 | . { process { if ($null -ne $_.DisplayName) { $_ } } } | ` 9 | Where-Object { $_.SystemComponent -ne 1 } | ` 10 | Select-Object -Property @{n = "Name"; e = { $_.DisplayName } }, @{n = "Version"; e = { $_.DisplayVersion } }, "Publisher", 11 | "UninstallString", @{n = "RegistryPath"; e = { $_.PSPath -replace "Microsoft.PowerShell.Core\\Registry::", "" } }, 12 | "PSChildName", "WindowsInstaller", "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize" | ` 13 | Sort-Object -Property "Name", "Publisher" 14 | } 15 | } 16 | 17 | Get-InstalledSoftware | Where-Object { $_.Name -match "Paint.NET*" } | ForEach-Object { 18 | $Context.Log("Uninstalling Windows Installer: $($_.PSChildName)") 19 | $params = @{ 20 | FilePath = "$Env:SystemRoot\System32\msiexec.exe" 21 | ArgumentList = "/uninstall `"$($_.PSChildName)`" /quiet /norestart" 22 | Wait = $true 23 | PassThru = $true 24 | NoNewWindow = $true 25 | ErrorAction = "Stop" 26 | } 27 | $result = Start-Process @params 28 | $Context.Log("Uninstall complete. Return code: $($result.ExitCode)") 29 | } 30 | -------------------------------------------------------------------------------- /shell-apps/Adobe/AcrobatReader/Uninstall.ps1: -------------------------------------------------------------------------------- 1 | function Get-InstalledSoftware { 2 | $PropertyNames = "DisplayName", "DisplayVersion", "Publisher", "UninstallString", "PSPath", "WindowsInstaller", 3 | "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize", "SystemComponent" 4 | ("HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", 5 | "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*") | ` 6 | ForEach-Object { 7 | Get-ItemProperty -Path $_ -Name $PropertyNames -ErrorAction "SilentlyContinue" | ` 8 | . { process { if ($null -ne $_.DisplayName) { $_ } } } | ` 9 | Where-Object { $_.SystemComponent -ne 1 } | ` 10 | Select-Object -Property @{n = "Name"; e = { $_.DisplayName } }, @{n = "Version"; e = { $_.DisplayVersion } }, "Publisher", 11 | "UninstallString", @{n = "RegistryPath"; e = { $_.PSPath -replace "Microsoft.PowerShell.Core\\Registry::", "" } }, 12 | "PSChildName", "WindowsInstaller", "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize" | ` 13 | Sort-Object -Property "Name", "Publisher" 14 | } 15 | } 16 | 17 | Get-InstalledSoftware | Where-Object { $_.Name -match "Adobe Acrobat*" } | ForEach-Object { 18 | $Context.Log("Uninstalling Windows Installer: $($_.PSChildName)") 19 | $params = @{ 20 | FilePath = "$Env:SystemRoot\System32\msiexec.exe" 21 | ArgumentList = "/uninstall `"$($_.PSChildName)`" /quiet /norestart" 22 | Wait = $true 23 | PassThru = $true 24 | NoNewWindow = $true 25 | ErrorAction = "Stop" 26 | } 27 | $result = Start-Process @params 28 | $Context.Log("Uninstall complete. Return code: $($result.ExitCode)") 29 | } 30 | -------------------------------------------------------------------------------- /shell-apps/Foxit/PDFReader/Uninstall.ps1: -------------------------------------------------------------------------------- 1 | function Get-InstalledSoftware { 2 | $PropertyNames = "DisplayName", "DisplayVersion", "Publisher", "UninstallString", "PSPath", "WindowsInstaller", 3 | "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize", "SystemComponent" 4 | ("HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", 5 | "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*") | ` 6 | ForEach-Object { 7 | Get-ItemProperty -Path $_ -Name $PropertyNames -ErrorAction "SilentlyContinue" | ` 8 | . { process { if ($null -ne $_.DisplayName) { $_ } } } | ` 9 | Where-Object { $_.SystemComponent -ne 1 } | ` 10 | Select-Object -Property @{n = "Name"; e = { $_.DisplayName } }, @{n = "Version"; e = { $_.DisplayVersion } }, "Publisher", 11 | "UninstallString", @{n = "RegistryPath"; e = { $_.PSPath -replace "Microsoft.PowerShell.Core\\Registry::", "" } }, 12 | "PSChildName", "WindowsInstaller", "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize" | ` 13 | Sort-Object -Property "Name", "Publisher" 14 | } 15 | } 16 | 17 | Get-InstalledSoftware | Where-Object { $_.Name -match "Foxit PDF Reader*" } | ForEach-Object { 18 | $Context.Log("Uninstalling Windows Installer: $($_.PSChildName)") 19 | $params = @{ 20 | FilePath = "$Env:SystemRoot\System32\msiexec.exe" 21 | ArgumentList = "/uninstall `"$($_.PSChildName)`" /quiet /norestart" 22 | Wait = $true 23 | PassThru = $true 24 | NoNewWindow = $true 25 | ErrorAction = "Stop" 26 | } 27 | $result = Start-Process @params 28 | $Context.Log("Uninstall complete. Return code: $($result.ExitCode)") 29 | } 30 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/PowerShell/Detect.ps1: -------------------------------------------------------------------------------- 1 | # Variables 2 | [System.String] $FilePath = "${Env:ProgramFiles}\PowerShell\7\pwsh.exe" 3 | 4 | # Detection logic 5 | if ([System.String]::IsNullOrEmpty($Context.TargetVersion)) { 6 | # This should be an uninstall action 7 | if (Test-Path -Path $FilePath) { return $true } 8 | else { 9 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 10 | } 11 | } 12 | else { 13 | # This should be an install action, so we need to check the file version 14 | if (Test-Path -Path $FilePath) { 15 | $Context.Log("File found: $FilePath") 16 | $FileItem = Get-ChildItem -Path $FilePath -ErrorAction "SilentlyContinue" 17 | $FileInfo = [Diagnostics.FileVersionInfo]::GetVersionInfo($FileItem.FullName) 18 | $Context.Log("File product version: $($FileInfo.FileVersion)") 19 | $Context.Log("Target Shell App version: $($Context.TargetVersion)") 20 | if ([System.Version]::Parse($FileInfo.FileVersion) -ge [System.Version]::Parse($Context.TargetVersion)) { 21 | $Context.Log("No update required. Found '$($FileInfo.FileVersion)' against '$($Context.TargetVersion)'.") 22 | if ($Context.Versions -is [System.Array]) { return $FileInfo.FileVersion } else { return $true } 23 | } 24 | else { 25 | $Context.Log("Update required. Found '$($FileInfo.FileVersion)' less than '$($Context.TargetVersion)'.") 26 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 27 | } 28 | } 29 | else { 30 | $Context.Log("File does not exist at: $($FilePath)") 31 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /shell-apps/Obsidian/Detect.ps1: -------------------------------------------------------------------------------- 1 | # Variables 2 | [System.String] $FilePath = "${Env:ProgramFiles}\Obsidian\Obsidian.exe" 3 | 4 | # Detection logic 5 | if ([System.String]::IsNullOrEmpty($Context.TargetVersion)) { 6 | # This should be an uninstall action 7 | if (Test-Path -Path $FilePath) { return $true } 8 | else { 9 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 10 | } 11 | } 12 | else { 13 | # This should be an install action, so we need to check the file version 14 | if (Test-Path -Path $FilePath) { 15 | $Context.Log("File found: $FilePath") 16 | $FileItem = Get-ChildItem -Path $FilePath -ErrorAction "SilentlyContinue" 17 | $FileInfo = [Diagnostics.FileVersionInfo]::GetVersionInfo($FileItem.FullName) 18 | $Context.Log("File product version: $($FileInfo.ProductVersion)") 19 | $Context.Log("Target Shell App version: $($Context.TargetVersion)") 20 | if ([System.Version]::Parse($FileInfo.ProductVersion) -ge [System.Version]::Parse($Context.TargetVersion)) { 21 | $Context.Log("No update required. Found '$($FileInfo.ProductVersion)' against '$($Context.TargetVersion)'.") 22 | if ($Context.Versions -is [System.Array]) { return $FileInfo.ProductVersion } else { return $true } 23 | } 24 | else { 25 | $Context.Log("Update required. Found '$($FileInfo.ProductVersion)' less than '$($Context.TargetVersion)'.") 26 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 27 | } 28 | } 29 | else { 30 | $Context.Log("File does not exist at: $($FilePath)") 31 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /shell-apps/JGraph/draw.io/Detect.ps1: -------------------------------------------------------------------------------- 1 | # Variables 2 | [System.String] $FilePath = "${Env:ProgramFiles}\draw.io\draw.io.exe" 3 | 4 | # Detection logic 5 | if ([System.String]::IsNullOrEmpty($Context.TargetVersion)) { 6 | # This should be an uninstall action 7 | if (Test-Path -Path $FilePath) { return $true } 8 | else { 9 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 10 | } 11 | } 12 | else { 13 | # This should be an install action, so we need to check the file version 14 | if (Test-Path -Path $FilePath) { 15 | $Context.Log("File found: $FilePath") 16 | $FileItem = Get-ChildItem -Path $FilePath -ErrorAction "SilentlyContinue" 17 | $FileInfo = [Diagnostics.FileVersionInfo]::GetVersionInfo($FileItem.FullName) 18 | $Context.Log("File product version: $($FileInfo.ProductVersion)") 19 | $Context.Log("Target Shell App version: $($Context.TargetVersion)") 20 | if ([System.Version]::Parse($FileInfo.ProductVersion) -ge [System.Version]::Parse($Context.TargetVersion)) { 21 | $Context.Log("No update required. Found '$($FileInfo.ProductVersion)' against '$($Context.TargetVersion)'.") 22 | if ($Context.Versions -is [System.Array]) { return $FileInfo.ProductVersion } else { return $true } 23 | } 24 | else { 25 | $Context.Log("Update required. Found '$($FileInfo.ProductVersion)' less than '$($Context.TargetVersion)'.") 26 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 27 | } 28 | } 29 | else { 30 | $Context.Log("File does not exist at: $($FilePath)") 31 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /shell-apps/Zoom/Workplace/Detect.ps1: -------------------------------------------------------------------------------- 1 | # Variables 2 | [System.String] $FilePath = "${Env:ProgramFiles}\Zoom\bin\Zoom.exe" 3 | 4 | # Detection logic 5 | if ([System.String]::IsNullOrEmpty($Context.TargetVersion)) { 6 | # This should be an uninstall action 7 | if (Test-Path -Path $FilePath) { return $true } 8 | else { 9 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 10 | } 11 | } 12 | else { 13 | # This should be an install action, so we need to check the file version 14 | if (Test-Path -Path $FilePath) { 15 | $Context.Log("File found: $FilePath") 16 | $FileItem = Get-ChildItem -Path $FilePath -ErrorAction "SilentlyContinue" 17 | $FileInfo = [Diagnostics.FileVersionInfo]::GetVersionInfo($FileItem.FullName) 18 | $Context.Log("File product version: $($FileInfo.ProductVersion)") 19 | $Context.Log("Target Shell App version: $($Context.TargetVersion)") 20 | if ([System.Version]::Parse($FileInfo.ProductVersion) -ge [System.Version]::Parse($Context.TargetVersion)) { 21 | $Context.Log("No update required. Found '$($FileInfo.ProductVersion)' against '$($Context.TargetVersion)'.") 22 | if ($Context.Versions -is [System.Array]) { return $FileInfo.ProductVersion } else { return $true } 23 | } 24 | else { 25 | $Context.Log("Update required. Found '$($FileInfo.ProductVersion)' less than '$($Context.TargetVersion)'.") 26 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 27 | } 28 | } 29 | else { 30 | $Context.Log("File does not exist at: $($FilePath)") 31 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /shell-apps/dotPDN/Paint.NET/Detect.ps1: -------------------------------------------------------------------------------- 1 | # Variables 2 | [System.String] $FilePath = "${Env:ProgramFiles}\Paint.NET\paintdotnet.exe" 3 | 4 | # Detection logic 5 | if ([System.String]::IsNullOrEmpty($Context.TargetVersion)) { 6 | # This should be an uninstall action 7 | if (Test-Path -Path $FilePath) { return $true } 8 | else { 9 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 10 | } 11 | } 12 | else { 13 | # This should be an install action, so we need to check the file version 14 | if (Test-Path -Path $FilePath) { 15 | $Context.Log("File found: $FilePath") 16 | $FileItem = Get-ChildItem -Path $FilePath -ErrorAction "SilentlyContinue" 17 | $FileInfo = [Diagnostics.FileVersionInfo]::GetVersionInfo($FileItem.FullName) 18 | $Context.Log("File product version: $($FileInfo.ProductVersion)") 19 | $Context.Log("Target Shell App version: $($Context.TargetVersion)") 20 | if ([System.Version]::Parse($FileInfo.ProductVersion) -ge [System.Version]::Parse($Context.TargetVersion)) { 21 | $Context.Log("No update required. Found '$($FileInfo.ProductVersion)' against '$($Context.TargetVersion)'.") 22 | if ($Context.Versions -is [System.Array]) { return $FileInfo.ProductVersion } else { return $true } 23 | } 24 | else { 25 | $Context.Log("Update required. Found '$($FileInfo.ProductVersion)' less than '$($Context.TargetVersion)'.") 26 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 27 | } 28 | } 29 | else { 30 | $Context.Log("File does not exist at: $($FilePath)") 31 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /actions/3rdparty/420_1Password.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Installs the 1Password Windows client. 4 | 5 | .DESCRIPTION 6 | This script installs the 1Password Windows client using the Evergreen module. 7 | It downloads the MSI installer from the specified URI and installs it silently. 8 | The installation log is saved in the specified log file. 9 | 10 | .PARAMETER Path 11 | The download path for the 1Password client. The default path is "$Env:SystemDrive\Apps\AgileBits\1Password". 12 | #> 13 | 14 | #description: Installs the 1Password Windows client 15 | #execution mode: Combined 16 | #tags: Evergreen, AgileBits, 1Password 17 | #Requires -Modules Evergreen 18 | [System.String] $Path = "$Env:SystemDrive\Apps\AgileBits\1Password" 19 | New-Item -Path $Path -ItemType "Directory" -Force -ErrorAction "SilentlyContinue" | Out-Null 20 | 21 | # Import shared functions written to disk by 000_PrepImage.ps1 22 | $FunctionFile = "$Env:TEMP\NerdioFunctions.psm1" 23 | Import-Module -Name $FunctionFile -Force -ErrorAction "Stop" 24 | Write-LogFile -Message "Functions imported from: $FunctionFile" 25 | 26 | # Download 27 | Write-LogFile -Message "Query Evergreen for 1Password client" 28 | $App = Get-EvergreenApp -Name "1Password" | Where-Object { $_.Type -eq "msi" } | Select-Object -First 1 29 | Write-LogFile -Message "Downloading 1Password version $($App.Version) to $Path" 30 | $OutFile = Save-EvergreenApp -InputObject $App -CustomPath $Path -ErrorAction "Stop" 31 | 32 | # Install package 33 | $LogPath = (Get-LogFile).Path 34 | $LogFile = "$LogPath\1Password.log" -replace " ", "" 35 | $params = @{ 36 | FilePath = "$Env:SystemRoot\System32\msiexec.exe" 37 | ArgumentList = "/package `"$($OutFile.FullName)`" /quiet /log $LogFile" 38 | } 39 | Start-ProcessWithLog @params 40 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/SupportCenter/Uninstall.ps1: -------------------------------------------------------------------------------- 1 | function Get-InstalledSoftware { 2 | $PropertyNames = "DisplayName", "DisplayVersion", "Publisher", "UninstallString", "PSPath", "WindowsInstaller", 3 | "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize", "SystemComponent" 4 | ("HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", 5 | "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*") | ` 6 | ForEach-Object { 7 | Get-ItemProperty -Path $_ -Name $PropertyNames -ErrorAction "SilentlyContinue" | ` 8 | . { process { if ($null -ne $_.DisplayName) { $_ } } } | ` 9 | Where-Object { $_.SystemComponent -ne 1 } | ` 10 | Select-Object -Property @{n = "Name"; e = { $_.DisplayName } }, @{n = "Version"; e = { $_.DisplayVersion } }, "Publisher", 11 | "UninstallString", @{n = "RegistryPath"; e = { $_.PSPath -replace "Microsoft.PowerShell.Core\\Registry::", "" } }, 12 | "PSChildName", "WindowsInstaller", "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize" | ` 13 | Sort-Object -Property "Name", "Publisher" 14 | } 15 | } 16 | 17 | Get-InstalledSoftware | Where-Object { $_.Name -match "Configuration Manager Support Center*" } | ForEach-Object { 18 | $Context.Log("Uninstalling Windows Installer: $($_.PSChildName)") 19 | $params = @{ 20 | FilePath = "$Env:SystemRoot\System32\msiexec.exe" 21 | ArgumentList = "/uninstall `"$($_.PSChildName)`" /quiet /norestart" 22 | Wait = $true 23 | PassThru = $true 24 | NoNewWindow = $true 25 | ErrorAction = "Stop" 26 | } 27 | $result = Start-Process @params 28 | $Context.Log("Uninstall complete. Return code: $($result.ExitCode)") 29 | } 30 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/VisualStudioCode/Detect.ps1: -------------------------------------------------------------------------------- 1 | # Variables 2 | [System.String] $FilePath = "${Env:ProgramFiles}\Microsoft VS Code\Code.exe" 3 | 4 | # Detection logic 5 | if ([System.String]::IsNullOrEmpty($Context.TargetVersion)) { 6 | # This should be an uninstall action 7 | if (Test-Path -Path $FilePath) { return $true } 8 | else { 9 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 10 | } 11 | } 12 | else { 13 | # This should be an install action, so we need to check the file version 14 | if (Test-Path -Path $FilePath) { 15 | $Context.Log("File found: $FilePath") 16 | $FileItem = Get-ChildItem -Path $FilePath -ErrorAction "SilentlyContinue" 17 | $FileInfo = [Diagnostics.FileVersionInfo]::GetVersionInfo($FileItem.FullName) 18 | $Context.Log("File product version: $($FileInfo.ProductVersion)") 19 | $Context.Log("Target Shell App version: $($Context.TargetVersion)") 20 | if ([System.Version]::Parse($FileInfo.ProductVersion) -ge [System.Version]::Parse($Context.TargetVersion)) { 21 | $Context.Log("No update required. Found '$($FileInfo.ProductVersion)' against '$($Context.TargetVersion)'.") 22 | if ($Context.Versions -is [System.Array]) { return $FileInfo.ProductVersion } else { return $true } 23 | } 24 | else { 25 | $Context.Log("Update required. Found '$($FileInfo.ProductVersion)' less than '$($Context.TargetVersion)'.") 26 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 27 | } 28 | } 29 | else { 30 | $Context.Log("File does not exist at: $($FilePath)") 31 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /shell-apps/Adobe/AcrobatReader/Detect.ps1: -------------------------------------------------------------------------------- 1 | # Variables 2 | [System.String] $FilePath = "${Env:ProgramFiles}\Adobe\Acrobat DC\Acrobat\Acrobat.exe" 3 | 4 | # Detection logic 5 | if ([System.String]::IsNullOrEmpty($Context.TargetVersion)) { 6 | # This should be an uninstall action 7 | if (Test-Path -Path $FilePath) { return $true } 8 | else { 9 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 10 | } 11 | } 12 | else { 13 | # This should be an install action, so we need to check the file version 14 | if (Test-Path -Path $FilePath) { 15 | $Context.Log("File found: $FilePath") 16 | $FileItem = Get-ChildItem -Path $FilePath -ErrorAction "SilentlyContinue" 17 | $FileInfo = [Diagnostics.FileVersionInfo]::GetVersionInfo($FileItem.FullName) 18 | $Context.Log("File product version: $($FileInfo.ProductVersion)") 19 | $Context.Log("Target Shell App version: $($Context.TargetVersion)") 20 | if ([System.Version]::Parse($FileInfo.ProductVersion) -ge [System.Version]::Parse($Context.TargetVersion)) { 21 | $Context.Log("No update required. Found '$($FileInfo.ProductVersion)' against '$($Context.TargetVersion)'.") 22 | if ($Context.Versions -is [System.Array]) { return $FileInfo.ProductVersion } else { return $true } 23 | } 24 | else { 25 | $Context.Log("Update required. Found '$($FileInfo.ProductVersion)' less than '$($Context.TargetVersion)'.") 26 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 27 | } 28 | } 29 | else { 30 | $Context.Log("File does not exist at: $($FilePath)") 31 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/AvdRtcService/Uninstall.ps1: -------------------------------------------------------------------------------- 1 | function Get-InstalledSoftware { 2 | $PropertyNames = "DisplayName", "DisplayVersion", "Publisher", "UninstallString", "PSPath", "WindowsInstaller", 3 | "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize", "SystemComponent" 4 | ("HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", 5 | "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*") | ` 6 | ForEach-Object { 7 | Get-ItemProperty -Path $_ -Name $PropertyNames -ErrorAction "SilentlyContinue" | ` 8 | . { process { if ($null -ne $_.DisplayName) { $_ } } } | ` 9 | Where-Object { $_.SystemComponent -ne 1 } | ` 10 | Select-Object -Property @{n = "Name"; e = { $_.DisplayName } }, @{n = "Version"; e = { $_.DisplayVersion } }, "Publisher", 11 | "UninstallString", @{n = "RegistryPath"; e = { $_.PSPath -replace "Microsoft.PowerShell.Core\\Registry::", "" } }, 12 | "PSChildName", "WindowsInstaller", "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize" | ` 13 | Sort-Object -Property "Name", "Publisher" 14 | } 15 | } 16 | 17 | Get-InstalledSoftware | Where-Object { $_.Name -match "Remote Desktop WebRTC Redirector Service*" } | ForEach-Object { 18 | $Context.Log("Uninstalling Windows Installer: $($_.PSChildName)") 19 | $params = @{ 20 | FilePath = "$Env:SystemRoot\System32\msiexec.exe" 21 | ArgumentList = "/uninstall `"$($_.PSChildName)`" /quiet /norestart" 22 | Wait = $true 23 | PassThru = $true 24 | NoNewWindow = $true 25 | ErrorAction = "Stop" 26 | } 27 | $result = Start-Process @params 28 | $Context.Log("Uninstall complete. Return code: $($result.ExitCode)") 29 | } 30 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/AvdMultimediaRedirection/Detect.ps1: -------------------------------------------------------------------------------- 1 | # Variables 2 | [System.String] $FilePath = "${Env:ProgramFiles}\MsRDCMMRHost\MsMmrHost.exe" 3 | 4 | # Detection logic 5 | if ([System.String]::IsNullOrEmpty($Context.TargetVersion)) { 6 | # This should be an uninstall action 7 | if (Test-Path -Path $FilePath) { return $true } 8 | else { 9 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 10 | } 11 | } 12 | else { 13 | # This should be an install action, so we need to check the file version 14 | if (Test-Path -Path $FilePath) { 15 | $Context.Log("File found: $FilePath") 16 | $FileItem = Get-ChildItem -Path $FilePath -ErrorAction "SilentlyContinue" 17 | $FileInfo = [Diagnostics.FileVersionInfo]::GetVersionInfo($FileItem.FullName) 18 | $Context.Log("File product version: $($FileInfo.ProductVersion)") 19 | $Context.Log("Target Shell App version: $($Context.TargetVersion)") 20 | if ([System.Version]::Parse($FileInfo.ProductVersion) -ge [System.Version]::Parse($Context.TargetVersion)) { 21 | $Context.Log("No update required. Found '$($FileInfo.ProductVersion)' against '$($Context.TargetVersion)'.") 22 | if ($Context.Versions -is [System.Array]) { return $FileInfo.ProductVersion } else { return $true } 23 | } 24 | else { 25 | $Context.Log("Update required. Found '$($FileInfo.ProductVersion)' less than '$($Context.TargetVersion)'.") 26 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 27 | } 28 | } 29 | else { 30 | $Context.Log("File does not exist at: $($FilePath)") 31 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /shell-apps/Foxit/PDFReader/Detect.ps1: -------------------------------------------------------------------------------- 1 | # Variables 2 | [System.String] $FilePath = "${Env:ProgramFiles(x86)}\Foxit Software\Foxit PDF Reader\FoxitPDFReader.exe" 3 | 4 | # Detection logic 5 | if ([System.String]::IsNullOrEmpty($Context.TargetVersion)) { 6 | # This should be an uninstall action 7 | if (Test-Path -Path $FilePath) { return $true } 8 | else { 9 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 10 | } 11 | } 12 | else { 13 | # This should be an install action, so we need to check the file version 14 | if (Test-Path -Path $FilePath) { 15 | $Context.Log("File found: $FilePath") 16 | $FileItem = Get-ChildItem -Path $FilePath -ErrorAction "SilentlyContinue" 17 | $FileInfo = [Diagnostics.FileVersionInfo]::GetVersionInfo($FileItem.FullName) 18 | $Context.Log("File product version: $($FileInfo.ProductVersion)") 19 | $Context.Log("Target Shell App version: $($Context.TargetVersion)") 20 | if ([System.Version]::Parse($FileInfo.ProductVersion) -ge [System.Version]::Parse($Context.TargetVersion)) { 21 | $Context.Log("No update required. Found '$($FileInfo.ProductVersion)' against '$($Context.TargetVersion)'.") 22 | if ($Context.Versions -is [System.Array]) { return $FileInfo.ProductVersion } else { return $true } 23 | } 24 | else { 25 | $Context.Log("Update required. Found '$($FileInfo.ProductVersion)' less than '$($Context.TargetVersion)'.") 26 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 27 | } 28 | } 29 | else { 30 | $Context.Log("File does not exist at: $($FilePath)") 31 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/AvdMultimediaRedirection/Uninstall.ps1: -------------------------------------------------------------------------------- 1 | function Get-InstalledSoftware { 2 | $PropertyNames = "DisplayName", "DisplayVersion", "Publisher", "UninstallString", "PSPath", "WindowsInstaller", 3 | "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize", "SystemComponent" 4 | ("HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", 5 | "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*") | ` 6 | ForEach-Object { 7 | Get-ItemProperty -Path $_ -Name $PropertyNames -ErrorAction "SilentlyContinue" | ` 8 | . { process { if ($null -ne $_.DisplayName) { $_ } } } | ` 9 | Where-Object { $_.SystemComponent -ne 1 } | ` 10 | Select-Object -Property @{n = "Name"; e = { $_.DisplayName } }, @{n = "Version"; e = { $_.DisplayVersion } }, "Publisher", 11 | "UninstallString", @{n = "RegistryPath"; e = { $_.PSPath -replace "Microsoft.PowerShell.Core\\Registry::", "" } }, 12 | "PSChildName", "WindowsInstaller", "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize" | ` 13 | Sort-Object -Property "Name", "Publisher" 14 | } 15 | } 16 | 17 | Get-InstalledSoftware | Where-Object { $_.Name -match "Remote Desktop Multimedia Redirection Service*" } | ForEach-Object { 18 | $Context.Log("Uninstalling Windows Installer: $($_.PSChildName)") 19 | $params = @{ 20 | FilePath = "$Env:SystemRoot\System32\msiexec.exe" 21 | ArgumentList = "/uninstall `"$($_.PSChildName)`" /quiet /norestart" 22 | Wait = $true 23 | PassThru = $true 24 | NoNewWindow = $true 25 | ErrorAction = "Stop" 26 | } 27 | $result = Start-Process @params 28 | $Context.Log("Uninstall complete. Return code: $($result.ExitCode)") 29 | } 30 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/AvdRtcService/Detect.ps1: -------------------------------------------------------------------------------- 1 | # Variables 2 | [System.String] $FilePath = "${Env:ProgramFiles}\Remote Desktop WebRTC Redirector\MsRdcWebRTCSvc.exe" 3 | 4 | # Detection logic 5 | if ([System.String]::IsNullOrEmpty($Context.TargetVersion)) { 6 | # This should be an uninstall action 7 | if (Test-Path -Path $FilePath) { return $true } 8 | else { 9 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 10 | } 11 | } 12 | else { 13 | # This should be an install action, so we need to check the file version 14 | if (Test-Path -Path $FilePath) { 15 | $Context.Log("File found: $FilePath") 16 | $FileItem = Get-ChildItem -Path $FilePath -ErrorAction "SilentlyContinue" 17 | $FileInfo = [Diagnostics.FileVersionInfo]::GetVersionInfo($FileItem.FullName) 18 | $Context.Log("File product version: $($FileInfo.ProductVersion)") 19 | $Context.Log("Target Shell App version: $($Context.TargetVersion)") 20 | if ([System.Version]::Parse($FileInfo.ProductVersion) -ge [System.Version]::Parse($Context.TargetVersion)) { 21 | $Context.Log("No update required. Found '$($FileInfo.ProductVersion)' against '$($Context.TargetVersion)'.") 22 | if ($Context.Versions -is [System.Array]) { return $FileInfo.ProductVersion } else { return $true } 23 | } 24 | else { 25 | $Context.Log("Update required. Found '$($FileInfo.ProductVersion)' less than '$($Context.TargetVersion)'.") 26 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 27 | } 28 | } 29 | else { 30 | $Context.Log("File does not exist at: $($FilePath)") 31 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/PowerShell/Uninstall.ps1: -------------------------------------------------------------------------------- 1 | [System.String] $Name = "PowerShell 7" 2 | 3 | function Get-InstalledSoftware { 4 | $PropertyNames = "DisplayName", "DisplayVersion", "Publisher", "UninstallString", "PSPath", "WindowsInstaller", 5 | "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize", "SystemComponent" 6 | ("HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", 7 | "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*") | ` 8 | ForEach-Object { 9 | Get-ItemProperty -Path $_ -Name $PropertyNames -ErrorAction "SilentlyContinue" | ` 10 | . { process { if ($null -ne $_.DisplayName) { $_ } } } | ` 11 | Where-Object { $_.SystemComponent -ne 1 } | ` 12 | Select-Object -Property @{n = "Name"; e = { $_.DisplayName } }, @{n = "Version"; e = { $_.DisplayVersion } }, "Publisher", 13 | "UninstallString", @{n = "RegistryPath"; e = { $_.PSPath -replace "Microsoft.PowerShell.Core\\Registry::", "" } }, 14 | "PSChildName", "WindowsInstaller", "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize" | ` 15 | Sort-Object -Property "Name", "Publisher" 16 | } 17 | } 18 | 19 | Get-InstalledSoftware | Where-Object { $_.Name -match "$Name*" } | ForEach-Object { 20 | $Context.Log("Uninstalling Windows Installer: $($_.PSChildName)") 21 | $params = @{ 22 | FilePath = "$Env:SystemRoot\System32\msiexec.exe" 23 | ArgumentList = "/uninstall `"$($_.PSChildName)`" /quiet /norestart" 24 | Wait = $true 25 | PassThru = $true 26 | NoNewWindow = $true 27 | ErrorAction = "Stop" 28 | } 29 | $result = Start-Process @params 30 | $Context.Log("Uninstall complete. Return code: $($result.ExitCode)") 31 | } 32 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/SupportCenter/Detect.ps1: -------------------------------------------------------------------------------- 1 | # Variables 2 | [System.String] $FilePath = "${Env:ProgramFiles(x86)}\Configuration Manager Support Center\ConfigMgrSupportCenterViewer.exe" 3 | 4 | # Detection logic 5 | if ([System.String]::IsNullOrEmpty($Context.TargetVersion)) { 6 | # This should be an uninstall action 7 | if (Test-Path -Path $FilePath) { return $true } 8 | else { 9 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 10 | } 11 | } 12 | else { 13 | # This should be an install action, so we need to check the file version 14 | if (Test-Path -Path $FilePath) { 15 | $Context.Log("File found: $FilePath") 16 | $FileItem = Get-ChildItem -Path $FilePath -ErrorAction "SilentlyContinue" 17 | $FileInfo = [Diagnostics.FileVersionInfo]::GetVersionInfo($FileItem.FullName) 18 | $Context.Log("File product version: $($FileInfo.ProductVersion)") 19 | $Context.Log("Target Shell App version: $($Context.TargetVersion)") 20 | if ([System.Version]::Parse($FileInfo.ProductVersion) -ge [System.Version]::Parse($Context.TargetVersion)) { 21 | $Context.Log("No update required. Found '$($FileInfo.ProductVersion)' against '$($Context.TargetVersion)'.") 22 | if ($Context.Versions -is [System.Array]) { return $FileInfo.ProductVersion } else { return $true } 23 | } 24 | else { 25 | $Context.Log("Update required. Found '$($FileInfo.ProductVersion)' less than '$($Context.TargetVersion)'.") 26 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 27 | } 28 | } 29 | else { 30 | $Context.Log("File does not exist at: $($FilePath)") 31 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/PowerToys/Detect.ps1: -------------------------------------------------------------------------------- 1 | # Variables 2 | [System.String] $FilePath = "${Env:ProgramFiles}\PowerToys\PowerToys.exe" 3 | 4 | # Detection logic 5 | if ([System.String]::IsNullOrEmpty($Context.TargetVersion)) { 6 | # This should be an uninstall action 7 | if (Test-Path -Path $FilePath) { return $true } 8 | else { 9 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 10 | } 11 | } 12 | else { 13 | # This should be an install action, so we need to check the file version 14 | if (Test-Path -Path $FilePath) { 15 | $Context.Log("File found: $FilePath") 16 | $FileItem = Get-ChildItem -Path $FilePath -ErrorAction "SilentlyContinue" 17 | $FileInfo = [Diagnostics.FileVersionInfo]::GetVersionInfo($FileItem.FullName) 18 | $Context.Log("File product version: $($FileInfo.ProductVersion)") 19 | $Context.Log("Target Shell App version: $($Context.TargetVersion)") 20 | if ([System.Version]::Parse($FileInfo.ProductVersion) -ge [System.Version]::Parse($Context.TargetVersion)) { 21 | $Context.Log("No update required. Found '$($FileInfo.ProductVersion)' against '$($Context.TargetVersion)'.") 22 | if ($Context.Versions -is [System.Array]) { return ($FileInfo.ProductVersion.Substring(0, $FileInfo.ProductVersion.LastIndexOf('.'))) } else { return $true } 23 | } 24 | else { 25 | $Context.Log("Update required. Found '$($FileInfo.ProductVersion)' less than '$($Context.TargetVersion)'.") 26 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 27 | } 28 | } 29 | else { 30 | $Context.Log("File does not exist at: $($FilePath)") 31 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/SQLServerManagementStudio/Detect.ps1: -------------------------------------------------------------------------------- 1 | # Variables 2 | [System.String] $FilePath = "${Env:ProgramFiles(x86)}\Microsoft SQL Server Management Studio 20\Common7\IDE\Ssms.exe" 3 | 4 | # Detection logic 5 | if ([System.String]::IsNullOrEmpty($Context.TargetVersion)) { 6 | # This should be an uninstall action 7 | if (Test-Path -Path $FilePath) { return $true } 8 | else { 9 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 10 | } 11 | } 12 | else { 13 | # This should be an install action, so we need to check the file version 14 | if (Test-Path -Path $FilePath) { 15 | $Context.Log("File found: $FilePath") 16 | $FileItem = Get-ChildItem -Path $FilePath -ErrorAction "SilentlyContinue" 17 | $FileInfo = [Diagnostics.FileVersionInfo]::GetVersionInfo($FileItem.FullName) 18 | $Context.Log("File product version: $($FileInfo.ProductVersion)") 19 | $Context.Log("Target Shell App version: $($Context.TargetVersion)") 20 | if ([System.Version]::Parse($FileInfo.ProductVersion) -ge [System.Version]::Parse($Context.TargetVersion)) { 21 | $Context.Log("No update required. Found '$($FileInfo.ProductVersion)' against '$($Context.TargetVersion)'.") 22 | if ($Context.Versions -is [System.Array]) { return $FileInfo.ProductVersion } else { return $true } 23 | } 24 | else { 25 | $Context.Log("Update required. Found '$($FileInfo.ProductVersion)' less than '$($Context.TargetVersion)'.") 26 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 27 | } 28 | } 29 | else { 30 | $Context.Log("File does not exist at: $($FilePath)") 31 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /actions/optimise/Remove-UScheduleKeys.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .DESCRIPTION 3 | This script deletes registry keys associated with the Windows Update Orchestrator's 4 | UScheduler for specific applications such as DevHomeUpdate, OutlookUpdate, and MS_Outlook. 5 | 6 | Run script at initial session host deployment 7 | #> 8 | reg delete "HKLM\SOFTWARE\Microsoft\WindowsUpdate\Orchestrator\UScheduler_Oobe\DevHomeUpdate" /f *>$null 9 | reg delete "HKLM\SOFTWARE\Microsoft\WindowsUpdate\Orchestrator\UScheduler_Oobe\OutlookUpdate" /f *>$null 10 | reg delete "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Orchestrator\UScheduler\DevHomeUpdate" /f *>$null 11 | reg delete "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Orchestrator\UScheduler\OutlookUpdate" /f *>$null 12 | reg delete "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Orchestrator\UScheduler\MS_Outlook" /f *>$null 13 | 14 | # Testing store app updates 15 | # reg delete "HKLM\SOFTWARE\Microsoft\WindowsUpdate\Orchestrator\UScheduler_Oobe\LXP" /f *>$null 16 | # reg delete "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Orchestrator\UScheduler\LXP" /f *>$null 17 | # reg delete "HKLM\SOFTWARE\Microsoft\WindowsUpdate\Orchestrator\UScheduler_Oobe\IA" /f *>$null 18 | # reg delete "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Orchestrator\UScheduler\IA" /f *>$null 19 | # reg delete "HKLM\SOFTWARE\Microsoft\WindowsUpdate\Orchestrator\UScheduler_Oobe\CrossDeviceUpdate" /f *>$null 20 | # reg delete "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Orchestrator\UScheduler\CrossDeviceUpdate" /f *>$null 21 | # reg delete "HKLM\SOFTWARE\Microsoft\WindowsUpdate\Orchestrator\UScheduler_Oobe\TFLUpdate" /f *>$null 22 | # reg delete "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Orchestrator\UScheduler\TFLUpdate" /f *>$null 23 | -------------------------------------------------------------------------------- /shell-apps/Audacity/Uninstall.ps1: -------------------------------------------------------------------------------- 1 | function Get-InstalledSoftware { 2 | $PropertyNames = "DisplayName", "DisplayVersion", "Publisher", "UninstallString", "PSPath", "WindowsInstaller", 3 | "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize", "SystemComponent" 4 | ("HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", 5 | "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*") | ` 6 | ForEach-Object { 7 | Get-ItemProperty -Path $_ -Name $PropertyNames -ErrorAction "SilentlyContinue" | ` 8 | . { process { if ($null -ne $_.DisplayName) { $_ } } } | ` 9 | Where-Object { $_.SystemComponent -ne 1 } | ` 10 | Select-Object -Property @{n = "Name"; e = { $_.DisplayName } }, @{n = "Version"; e = { $_.DisplayVersion } }, "Publisher", 11 | "UninstallString", @{n = "RegistryPath"; e = { $_.PSPath -replace "Microsoft.PowerShell.Core\\Registry::", "" } }, 12 | "PSChildName", "WindowsInstaller", "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize" | ` 13 | Sort-Object -Property "Name", "Publisher" 14 | } 15 | } 16 | 17 | $Context.Log("Uninstalling Audacity)") 18 | $params = @{ 19 | FilePath = "${Env:ProgramFiles}\Audacity\unins000.exe" 20 | ArgumentList = "/VERYSILENT" 21 | Wait = $true 22 | PassThru = $true 23 | NoNewWindow = $true 24 | ErrorAction = "Stop" 25 | } 26 | $result = Start-Process @params 27 | $Context.Log("Uninstall complete. Return code: $($result.ExitCode)") 28 | 29 | $Shortcuts = @("$Env:ProgramData\Microsoft\Windows\Start Menu\Programs\Audacity.lnk") 30 | Get-Item -Path $Shortcuts -ErrorAction "SilentlyContinue" | ` 31 | ForEach-Object { $Context.Log("Remove file: $($_.FullName)"); Remove-Item -Path $_.FullName -Force -ErrorAction "SilentlyContinue" } 32 | -------------------------------------------------------------------------------- /actions/core/012_WindowsUpdate.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Installs all available Windows updates with PSWindowsUpdate. 4 | 5 | .DESCRIPTION 6 | This script installs all available Windows updates using the PSWindowsUpdate module. 7 | It first deletes the policy setting created by MDT and then proceeds to install the updates. 8 | The script uses the Install-WindowsUpdate cmdlet with the necessary parameters to accept all updates, 9 | include Microsoft updates, and ignore reboot requirements. 10 | 11 | .OUTPUTS 12 | The script outputs the Title and Size properties of the installed updates. 13 | #> 14 | 15 | #description: Installs all available Windows updates with PSWindowsUpdate 16 | #execution mode: Combined 17 | #tags: Update, Image 18 | #Requires -Modules PSWindowsUpdate 19 | 20 | # Import shared functions written to disk by 000_PrepImage.ps1 21 | $FunctionFile = "$Env:TEMP\NerdioFunctions.psm1" 22 | Import-Module -Name $FunctionFile -Force -ErrorAction "Stop" 23 | Write-LogFile -Message "Functions imported from: $FunctionFile" 24 | 25 | # Delete the policy setting created by MDT 26 | Start-ProcessWithLog -FilePath "$Env:SystemRoot\System32\reg.exe" -ArgumentList "delete HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU /f" 27 | 28 | # Install updates 29 | Write-LogFile -Message "Installing all available Windows updates with PSWindowsUpdate" 30 | Import-Module -Name "PSWindowsUpdate" 31 | $params = @{ 32 | Install = $true 33 | Download = $true 34 | AcceptAll = $true 35 | MicrosoftUpdate = $true 36 | IgnoreReboot = $true 37 | IgnoreRebootRequired = $true 38 | IgnoreUserInput = $true 39 | } 40 | Install-WindowsUpdate @params | Select-Object -Property "Title", "Size" | ForEach-Object { 41 | Write-LogFile -Message "Installed update: $($_.Title)" 42 | } 43 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/PowerToys/Uninstall.ps1: -------------------------------------------------------------------------------- 1 | function Get-InstalledSoftware { 2 | $PropertyNames = "DisplayName", "DisplayVersion", "Publisher", "UninstallString", "PSPath", "WindowsInstaller", 3 | "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize", "SystemComponent" 4 | ("HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", 5 | "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*") | ` 6 | ForEach-Object { 7 | Get-ItemProperty -Path $_ -Name $PropertyNames -ErrorAction "SilentlyContinue" | ` 8 | . { process { if ($null -ne $_.DisplayName) { $_ } } } | ` 9 | Where-Object { $_.SystemComponent -ne 1 } | ` 10 | Select-Object -Property @{n = "Name"; e = { $_.DisplayName } }, @{n = "Version"; e = { $_.DisplayVersion } }, "Publisher", 11 | "UninstallString", @{n = "RegistryPath"; e = { $_.PSPath -replace "Microsoft.PowerShell.Core\\Registry::", "" } }, 12 | "PSChildName", "WindowsInstaller", "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize" | ` 13 | Sort-Object -Property "Name", "Publisher" 14 | } 15 | } 16 | 17 | Get-InstalledSoftware | Where-Object { $_.Name -match "PowerToys*" } | ForEach-Object { 18 | if ($_.UninstallString -match '"([^"]+)"') { 19 | $Context.Log("Uninstall with: $($Matches[1])") 20 | $params = @{ 21 | FilePath = $Matches[1] 22 | ArgumentList = "/uninstall /quiet /norestart" 23 | Wait = $true 24 | PassThru = $true 25 | NoNewWindow = $true 26 | ErrorAction = "Stop" 27 | } 28 | $result = Start-Process @params 29 | $Context.Log("Uninstall complete. Return code: $($result.ExitCode)") 30 | } 31 | else { 32 | $Context.Log("Failed to parse UninstallString") 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/FSLogixApps/Detect.ps1: -------------------------------------------------------------------------------- 1 | # Variables 2 | [System.String] $FilePath = "${Env:ProgramFiles}\FSLogix\Apps\frxsvc.exe" 3 | 4 | # Detection logic 5 | if ([System.String]::IsNullOrEmpty($Context.TargetVersion)) { 6 | # This should be an uninstall action 7 | if (Test-Path -Path $FilePath) { return $true } 8 | else { 9 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 10 | } 11 | } 12 | else { 13 | if (Test-Path -Path $FilePath) { 14 | $FileItem = Get-ChildItem -Path $FilePath -ErrorAction "SilentlyContinue" 15 | $Context.Log("File found: $($FileItem.FullName)") 16 | 17 | # FSLogix version will be in the form of "25.06", so we need construct the version numbers to compare 18 | $FileInfo = [Diagnostics.FileVersionInfo]::GetVersionInfo($FileItem.FullName) 19 | $ProductVersion = [System.Version]::Parse("$($FileInfo.ProductVersion).0") 20 | $ContextVersion = [System.Version]::Parse("$($Context.TargetVersion).0") 21 | $CompareContextVersion = [System.Version]::Parse("3.$($ContextVersion.Major).0") 22 | 23 | if ($ProductVersion -ge $CompareContextVersion) { 24 | $Context.Log("No update required. Found '$($ProductVersion.ToString())' against '$($CompareContextVersion.ToString())'.") 25 | if ($Context.Versions -is [System.Array]) { return $Context.TargetVersion } else { return $true } 26 | } 27 | else { 28 | $Context.Log("Update required. Found '$($FileInfo.ProductVersion)' less than '$($Context.TargetVersion)'.") 29 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 30 | } 31 | } 32 | else { 33 | $Context.Log("File does not exist at: $($FilePath)") 34 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/FSLogixApps/Uninstall.ps1: -------------------------------------------------------------------------------- 1 | function Get-InstalledSoftware { 2 | $PropertyNames = "DisplayName", "DisplayVersion", "Publisher", "UninstallString", "PSPath", "WindowsInstaller", 3 | "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize", "SystemComponent" 4 | ("HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", 5 | "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*") | ` 6 | ForEach-Object { 7 | Get-ItemProperty -Path $_ -Name $PropertyNames -ErrorAction "SilentlyContinue" | ` 8 | . { process { if ($null -ne $_.DisplayName) { $_ } } } | ` 9 | Where-Object { $_.SystemComponent -ne 1 } | ` 10 | Select-Object -Property @{n = "Name"; e = { $_.DisplayName } }, @{n = "Version"; e = { $_.DisplayVersion } }, "Publisher", 11 | "UninstallString", @{n = "RegistryPath"; e = { $_.PSPath -replace "Microsoft.PowerShell.Core\\Registry::", "" } }, 12 | "PSChildName", "WindowsInstaller", "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize" | ` 13 | Sort-Object -Property "Name", "Publisher" 14 | } 15 | } 16 | 17 | Get-InstalledSoftware | Where-Object { $_.Name -match "Microsoft FSLogix Apps*" } | ForEach-Object { 18 | if ($_.UninstallString -match '"([^"]+)"') { 19 | $Context.Log("Uninstall with: $($Matches[1])") 20 | $params = @{ 21 | FilePath = $Matches[1] 22 | ArgumentList = "/uninstall /quiet /norestart" 23 | Wait = $true 24 | PassThru = $true 25 | NoNewWindow = $true 26 | ErrorAction = "Stop" 27 | } 28 | $result = Start-Process @params 29 | $Context.Log("Uninstall complete. Return code: $($result.ExitCode)") 30 | } 31 | else { 32 | $Context.Log("Failed to parse UninstallString") 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/NETLTS/Uninstall.ps1: -------------------------------------------------------------------------------- 1 | function Get-InstalledSoftware { 2 | $PropertyNames = "DisplayName", "DisplayVersion", "Publisher", "UninstallString", "PSPath", "WindowsInstaller", 3 | "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize", "SystemComponent" 4 | ("HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", 5 | "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*") | ` 6 | ForEach-Object { 7 | Get-ItemProperty -Path $_ -Name $PropertyNames -ErrorAction "SilentlyContinue" | ` 8 | . { process { if ($null -ne $_.DisplayName) { $_ } } } | ` 9 | Where-Object { $_.SystemComponent -ne 1 } | ` 10 | Select-Object -Property @{n = "Name"; e = { $_.DisplayName } }, @{n = "Version"; e = { $_.DisplayVersion } }, "Publisher", 11 | "UninstallString", @{n = "RegistryPath"; e = { $_.PSPath -replace "Microsoft.PowerShell.Core\\Registry::", "" } }, 12 | "PSChildName", "WindowsInstaller", "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize" | ` 13 | Sort-Object -Property "Name", "Publisher" 14 | } 15 | } 16 | 17 | Get-InstalledSoftware | Where-Object { $_.Name -match "Microsoft Windows Desktop Runtime*" } | ForEach-Object { 18 | if ($_.UninstallString -match '"([^"]+)"') { 19 | $Context.Log("Uninstall with: $($Matches[1])") 20 | $params = @{ 21 | FilePath = $Matches[1] 22 | ArgumentList = "/uninstall /quiet /norestart" 23 | Wait = $true 24 | PassThru = $true 25 | NoNewWindow = $true 26 | ErrorAction = "Stop" 27 | } 28 | $result = Start-Process @params 29 | $Context.Log("Uninstall complete. Return code: $($result.ExitCode)") 30 | } 31 | else { 32 | $Context.Log("Failed to parse UninstallString") 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/OneDrive/Uninstall.ps1: -------------------------------------------------------------------------------- 1 | function Get-InstalledSoftware { 2 | $PropertyNames = "DisplayName", "DisplayVersion", "Publisher", "UninstallString", "PSPath", "WindowsInstaller", 3 | "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize", "SystemComponent" 4 | ("HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", 5 | "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*") | ` 6 | ForEach-Object { 7 | Get-ItemProperty -Path $_ -Name $PropertyNames -ErrorAction "SilentlyContinue" | ` 8 | . { process { if ($null -ne $_.DisplayName) { $_ } } } | ` 9 | Where-Object { $_.SystemComponent -ne 1 } | ` 10 | Select-Object -Property @{n = "Name"; e = { $_.DisplayName } }, @{n = "Version"; e = { $_.DisplayVersion } }, "Publisher", 11 | "UninstallString", @{n = "RegistryPath"; e = { $_.PSPath -replace "Microsoft.PowerShell.Core\\Registry::", "" } }, 12 | "PSChildName", "WindowsInstaller", "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize" | ` 13 | Sort-Object -Property "Name", "Publisher" 14 | } 15 | } 16 | 17 | Get-InstalledSoftware | Where-Object { $_.Name -match "Microsoft OneDrive*" } | ForEach-Object { 18 | if ($_.UninstallString -match '"([^"]+)"') { 19 | $Context.Log("Uninstall with: $($Matches[1])") 20 | $params = @{ 21 | FilePath = $Matches[1] 22 | ArgumentList = "/uninstall /allusers /quiet /norestart" 23 | Wait = $true 24 | PassThru = $true 25 | NoNewWindow = $true 26 | ErrorAction = "Stop" 27 | } 28 | $result = Start-Process @params 29 | $Context.Log("Uninstall complete. Return code: $($result.ExitCode)") 30 | } 31 | else { 32 | $Context.Log("Failed to parse UninstallString") 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /shell-apps/Audacity/Detect.ps1: -------------------------------------------------------------------------------- 1 | # Variables 2 | [System.String] $FilePath = "${Env:ProgramFiles}\Audacity\Audacity.exe" 3 | 4 | # Detection logic 5 | if ([System.String]::IsNullOrEmpty($Context.TargetVersion)) { 6 | # This should be an uninstall action 7 | if (Test-Path -Path $FilePath) { return $true } 8 | else { 9 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 10 | } 11 | } 12 | else { 13 | # This should be an install action, so we need to check the file version 14 | if (Test-Path -Path $FilePath) { 15 | $Context.Log("File found: $FilePath") 16 | $FileItem = Get-ChildItem -Path $FilePath -ErrorAction "SilentlyContinue" 17 | $FileInfo = [Diagnostics.FileVersionInfo]::GetVersionInfo($FileItem.FullName) 18 | $FileVersion = [System.Version]::Parse(($FileInfo.ProductVersion -replace ",", ".")) 19 | $FileVersionJoin = $FileVersion.Major, $FileVersion.Minor, $FileVersion.Build -join "." 20 | $Context.Log("Found version: $FileVersionJoin") 21 | $Context.Log("Compare to: $($Context.TargetVersion)") 22 | if ([System.Version]::Parse($FileVersionJoin) -ge [System.Version]::Parse($Context.TargetVersion)) { 23 | $Context.Log("No update required. Found '$($FileInfo.ProductVersion)' against '$($Context.TargetVersion)'.") 24 | if ($Context.Versions -is [System.Array]) { return $FileInfo.ProductVersion } else { return $true } 25 | } 26 | else { 27 | $Context.Log("Update required. Found '$($FileInfo.ProductVersion)' less than '$($Context.TargetVersion)'.") 28 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 29 | } 30 | } 31 | else { 32 | $Context.Log("File does not exist at: $($FilePath)") 33 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 34 | } 35 | } -------------------------------------------------------------------------------- /shell-apps/Google/Chrome/Detect.ps1: -------------------------------------------------------------------------------- 1 | # Variables 2 | [System.String] $FilePath = "${Env:ProgramFiles}\Google\Chrome\Application\chrome.exe" 3 | [System.String] $PrefsPath = "${Env:ProgramFiles}\Google\Chrome\Application\initial_preferences" 4 | 5 | # Detection logic 6 | if ([System.String]::IsNullOrEmpty($Context.TargetVersion)) { 7 | # This should be an uninstall action 8 | if (Test-Path -Path $FilePath) { return $true } 9 | else { 10 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 11 | } 12 | } 13 | else { 14 | if (Test-Path -Path $FilePath) { 15 | if (Test-Path -Path $PrefsPath) { 16 | $FileItem = Get-ChildItem -Path $FilePath -ErrorAction "SilentlyContinue" 17 | $Context.Log("File found: $($FileItem.FullName)") 18 | $FileInfo = [Diagnostics.FileVersionInfo]::GetVersionInfo($FileItem.FullName) 19 | if ([System.Version]::Parse($FileInfo.ProductVersion) -ge [System.Version]::Parse($Context.TargetVersion)) { 20 | $Context.Log("No update required. Found '$($FileInfo.ProductVersion)' against '$($Context.TargetVersion)'.") 21 | if ($Context.Versions -is [System.Array]) { return $FileInfo.ProductVersion } else { return $true } 22 | } 23 | else { 24 | $Context.Log("Update required. Found '$($FileInfo.ProductVersion)' less than '$($Context.TargetVersion)'.") 25 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 26 | } 27 | } 28 | else { 29 | $Context.Log("File does not exist at: $($PrefsPath)") 30 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 31 | } 32 | } 33 | else { 34 | $Context.Log("File does not exist at: $($FilePath)") 35 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/Edge/Detect.ps1: -------------------------------------------------------------------------------- 1 | # Variables 2 | [System.String] $FilePath = "${Env:ProgramFiles(x86)}\Microsoft\Edge\Application\msedge.exe" 3 | [System.String] $PrefsPath = "${Env:ProgramFiles(x86)}\Microsoft\Edge\Application\initial_preferences" 4 | 5 | # Detection logic 6 | if ([System.String]::IsNullOrEmpty($Context.TargetVersion)) { 7 | # This should be an uninstall action 8 | if (Test-Path -Path $FilePath) { return $true } 9 | else { 10 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 11 | } 12 | } 13 | else { 14 | if (Test-Path -Path $FilePath) { 15 | if (Test-Path -Path $PrefsPath) { 16 | $FileItem = Get-ChildItem -Path $FilePath -ErrorAction "SilentlyContinue" 17 | $Context.Log("File found: $($FileItem.FullName)") 18 | $FileInfo = [Diagnostics.FileVersionInfo]::GetVersionInfo($FileItem.FullName) 19 | if ([System.Version]::Parse($FileInfo.ProductVersion) -ge [System.Version]::Parse($Context.TargetVersion)) { 20 | $Context.Log("No update required. Found '$($FileInfo.ProductVersion)' against '$($Context.TargetVersion)'.") 21 | if ($Context.Versions -is [System.Array]) { return $FileInfo.ProductVersion } else { return $true } 22 | } 23 | else { 24 | $Context.Log("Update required. Found '$($FileInfo.ProductVersion)' less than '$($Context.TargetVersion)'.") 25 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 26 | } 27 | } 28 | else { 29 | $Context.Log("File does not exist at: $($PrefsPath)") 30 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 31 | } 32 | } 33 | else { 34 | $Context.Log("File does not exist at: $($FilePath)") 35 | if ($Context.Versions -is [System.Array]) { return $null } else { return $false } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /actions/core/011_SupportFunctions.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Installs PowerShell modules required for building AVD images (Evergreen, VcRedist, PSWindowsUpdate, etc.) 4 | 5 | .DESCRIPTION 6 | This script installs the necessary PowerShell modules for building AVD (Azure Virtual Desktop) images. 7 | It ensures that the PSGallery is trusted, installs the required package providers, 8 | and then installs the Evergreen, VcRedist, and PSWindowsUpdate modules if they are not already installed or if a newer version is available. 9 | #> 10 | 11 | #description: Installs PowerShell modules required for building AVD images (Evergreen, VcRedist, PSWindowsUpdate, etc.) 12 | #execution mode: Combined 13 | #tags: Evergreen, VcRedist, Image 14 | 15 | # Import shared functions written to disk by 000_PrepImage.ps1 16 | $FunctionFile = "$Env:TEMP\NerdioFunctions.psm1" 17 | Import-Module -Name $FunctionFile -Force -ErrorAction "Stop" 18 | Write-LogFile -Message "Functions imported from: $FunctionFile" 19 | 20 | # Trust the PSGallery for modules 21 | Write-LogFile -Message "Install-PackageProvider: PowerShellGet" -LogLevel 1 22 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072 23 | Install-PackageProvider -Name "PowerShellGet" -MinimumVersion "2.2.5" -Force 24 | Write-LogFile -Message "Set-PSRepository: PSGallery" -LogLevel 1 25 | Set-PSRepository -Name "PSGallery" -InstallationPolicy "Trusted" 26 | 27 | # Evergreen: https://eucpilots.com/evergreen-docs/ 28 | # VcRedist: https://vcredist.com/ 29 | # PSWindowsUpdate: https://www.powershellgallery.com/packages/PSWindowsUpdate 30 | Set-PSRepository -Name "PSGallery" -InstallationPolicy "Trusted" 31 | Write-LogFile -Message "Install-Module: PSWindowsUpdate" -LogLevel 1 32 | Install-Module -Name "PSWindowsUpdate" -Force 33 | Write-LogFile -Message "Install-Module: VcRedist" -LogLevel 1 34 | Install-Module -Name "VcRedist" -Force 35 | Write-LogFile -Message "Install-Module: Evergreen" -LogLevel 1 36 | Install-Module -Name "Evergreen" -Force 37 | Update-Evergreen -Force 38 | -------------------------------------------------------------------------------- /nme/terraform/vnet.tf: -------------------------------------------------------------------------------- 1 | resource "azurerm_virtual_network" "nerdio" { 2 | name = "${lower(var.base_name)}-vnet" 3 | location = local.resource_group_location 4 | resource_group_name = local.resource_group_name 5 | 6 | address_space = var.vnet_address_space 7 | 8 | tags = var.tags 9 | } 10 | 11 | resource "azurerm_subnet" "private_endpoints" { 12 | name = "private-endpoints" 13 | virtual_network_name = azurerm_virtual_network.nerdio.name 14 | resource_group_name = azurerm_virtual_network.nerdio.resource_group_name 15 | address_prefixes = [cidrsubnet(azurerm_virtual_network.nerdio.address_space[0], 1, 0)] 16 | 17 | #private_endpoint_network_policies_enabled = true 18 | } 19 | 20 | resource "azurerm_subnet" "appsvc" { 21 | name = "appsvc" 22 | virtual_network_name = azurerm_virtual_network.nerdio.name 23 | resource_group_name = azurerm_virtual_network.nerdio.resource_group_name 24 | address_prefixes = [cidrsubnet(azurerm_virtual_network.nerdio.address_space[0], 1, 1)] 25 | 26 | delegation { 27 | name = "delegation" 28 | 29 | service_delegation { 30 | name = "Microsoft.Web/serverFarms" 31 | actions = ["Microsoft.Network/virtualNetworks/subnets/action"] 32 | } 33 | } 34 | } 35 | 36 | resource "azurerm_network_security_group" "nerdio" { 37 | name = "${lower(var.base_name)}-nsg" 38 | location = local.resource_group_location 39 | resource_group_name = local.resource_group_name 40 | 41 | tags = var.tags 42 | } 43 | 44 | resource "azurerm_subnet_network_security_group_association" "private_endpoints" { 45 | subnet_id = azurerm_subnet.private_endpoints.id 46 | network_security_group_id = azurerm_network_security_group.nerdio.id 47 | } 48 | 49 | resource "azurerm_subnet_network_security_group_association" "appsvc" { 50 | subnet_id = azurerm_subnet.appsvc.id 51 | network_security_group_id = azurerm_network_security_group.nerdio.id 52 | } 53 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/VisualC++2022x64/Uninstall.ps1: -------------------------------------------------------------------------------- 1 | function Get-InstalledSoftware { 2 | $PropertyNames = "DisplayName", "DisplayVersion", "Publisher", "UninstallString", "PSPath", "WindowsInstaller", 3 | "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize", "SystemComponent" 4 | ("HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", 5 | "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*") | ` 6 | ForEach-Object { 7 | Get-ItemProperty -Path $_ -Name $PropertyNames -ErrorAction "SilentlyContinue" | ` 8 | . { process { if ($null -ne $_.DisplayName) { $_ } } } | ` 9 | Where-Object { $_.SystemComponent -ne 1 } | ` 10 | Select-Object -Property @{n = "Name"; e = { $_.DisplayName } }, @{n = "Version"; e = { $_.DisplayVersion } }, "Publisher", 11 | "UninstallString", @{n = "RegistryPath"; e = { $_.PSPath -replace "Microsoft.PowerShell.Core\\Registry::", "" } }, 12 | "PSChildName", "WindowsInstaller", "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize" | ` 13 | Sort-Object -Property "Name", "Publisher" 14 | } 15 | } 16 | 17 | Get-InstalledSoftware | Where-Object { $_.Name -match "Microsoft Visual C\+\+ 14 Redistributable (x64)*" } | ForEach-Object { 18 | if ($_.UninstallString -match '"([^"]+)"') { 19 | $Context.Log("Uninstall with: $($Matches[1])") 20 | $params = @{ 21 | FilePath = $Matches[1] 22 | ArgumentList = "/uninstall /quiet /norestart" 23 | Wait = $true 24 | PassThru = $true 25 | NoNewWindow = $true 26 | ErrorAction = "Stop" 27 | } 28 | $result = Start-Process @params 29 | $Context.Log("Remove file: ${Env:SystemRoot}\System32\vcruntime140.dll") 30 | Remove-Item -Path "${Env:SystemRoot}\System32\vcruntime140.dll" -ErrorAction "SilentlyContinue" 31 | $Context.Log("Uninstall complete. Return code: $($result.ExitCode)") 32 | } 33 | else { 34 | $Context.Log("Failed to parse UninstallString") 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/VisualC++2022x86/Uninstall.ps1: -------------------------------------------------------------------------------- 1 | function Get-InstalledSoftware { 2 | $PropertyNames = "DisplayName", "DisplayVersion", "Publisher", "UninstallString", "PSPath", "WindowsInstaller", 3 | "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize", "SystemComponent" 4 | ("HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", 5 | "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*") | ` 6 | ForEach-Object { 7 | Get-ItemProperty -Path $_ -Name $PropertyNames -ErrorAction "SilentlyContinue" | ` 8 | . { process { if ($null -ne $_.DisplayName) { $_ } } } | ` 9 | Where-Object { $_.SystemComponent -ne 1 } | ` 10 | Select-Object -Property @{n = "Name"; e = { $_.DisplayName } }, @{n = "Version"; e = { $_.DisplayVersion } }, "Publisher", 11 | "UninstallString", @{n = "RegistryPath"; e = { $_.PSPath -replace "Microsoft.PowerShell.Core\\Registry::", "" } }, 12 | "PSChildName", "WindowsInstaller", "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize" | ` 13 | Sort-Object -Property "Name", "Publisher" 14 | } 15 | } 16 | 17 | Get-InstalledSoftware | Where-Object { $_.Name -match "Microsoft Visual C\+\+ 14 Redistributable (x86)*" } | ForEach-Object { 18 | if ($_.UninstallString -match '"([^"]+)"') { 19 | $Context.Log("Uninstall with: $($Matches[1])") 20 | $params = @{ 21 | FilePath = $Matches[1] 22 | ArgumentList = "/uninstall /quiet /norestart" 23 | Wait = $true 24 | PassThru = $true 25 | NoNewWindow = $true 26 | ErrorAction = "Stop" 27 | } 28 | $result = Start-Process @params 29 | $Context.Log("Remove file: ${Env:SystemRoot}\SysWOW64\vcruntime140.dll") 30 | Remove-Item -Path "${Env:SystemRoot}\SysWOW64\vcruntime140.dll" -ErrorAction "SilentlyContinue" 31 | $Context.Log("Uninstall complete. Return code: $($result.ExitCode)") 32 | } 33 | else { 34 | $Context.Log("Failed to parse UninstallString") 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /actions/core/213_MicrosoftWindowsApp.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Installs the latest Microsoft Windows App. 4 | 5 | .DESCRIPTION 6 | This script installs the latest version of the Microsoft Windows App. 7 | It uses the Evergreen module to retrieve the appropriate version of the client and installs it silently. 8 | 9 | .PARAMETER Path 10 | The path where the Microsoft Windows App will be downloaded. 11 | The default path is "$Env:SystemDrive\Apps\Microsoft\Avd". 12 | 13 | .NOTES 14 | - This script requires the Evergreen module to be installed. 15 | - The script creates a log file in "$Env:SystemRoot\Logs\ImageBuild" to track the installation progress. 16 | - The script only installs the x64 version of the client from the "Public" channel. 17 | - The installation is performed silently without creating a desktop shortcut. 18 | #> 19 | 20 | #description: Installs the latest Microsoft Windows App 21 | #execution mode: Combined 22 | #tags: Evergreen, Microsoft, Remote Desktop 23 | #Requires -Modules Evergreen 24 | [System.String] $Path = "$Env:SystemDrive\Apps\Microsoft\Avd" 25 | New-Item -Path $Path -ItemType "Directory" -Force -ErrorAction "SilentlyContinue" | Out-Null 26 | 27 | # Import shared functions written to disk by 000_PrepImage.ps1 28 | $FunctionFile = "$Env:TEMP\NerdioFunctions.psm1" 29 | Import-Module -Name $FunctionFile -Force -ErrorAction "Stop" 30 | Write-LogFile -Message "Functions imported from: $FunctionFile" 31 | 32 | #region Script logic 33 | 34 | $App = Get-EvergreenApp -Name "MicrosoftWindowsApp" | ` 35 | Where-Object { $_.Architecture -eq "x64" } | Select-Object -First 1 36 | $OutFile = Save-EvergreenApp -InputObject $App -CustomPath $Path -ErrorAction "Stop" 37 | Write-LogFile -Message "Microsoft Windows App $($App.Version) downloaded to: $($OutFile.FullName)" 38 | 39 | Write-LogFile -Message "Starting Microsoft Windows App installation from: $($OutFile.FullName)" 40 | $params = @{ 41 | PackagePath = $OutFile.FullName 42 | Online = $true 43 | SkipLicense = $true 44 | ErrorAction = "Stop" 45 | } 46 | Add-AppxProvisionedPackage @params 47 | #endregion 48 | -------------------------------------------------------------------------------- /actions/3rdparty/402_ZoomMeetings.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Installs the latest Zoom Meetings VDI client. 4 | 5 | .DESCRIPTION 6 | This script installs the latest Zoom Meetings VDI client by downloading it using the Evergreen module and installing it silently using msiexec.exe. 7 | 8 | .PARAMETER Path 9 | The path where the Zoom Meetings VDI client will be downloaded. The default path is "$Env:SystemDrive\Apps\Zoom\Meetings". 10 | 11 | .NOTES 12 | - This script requires the Evergreen module to be installed. 13 | - The script creates a log file at "$Env:SystemRoot\Logs\ImageBuild\ZoomMeetings.log" to track the installation progress. 14 | - The script uses the Start-Process cmdlet to execute msiexec.exe with the necessary arguments for silent installation. 15 | #> 16 | 17 | #description: Installs the latest Zoom Meetings VDI client 18 | #execution mode: Combined 19 | #tags: Evergreen, Zoom 20 | #Requires -Modules Evergreen 21 | [System.String] $Path = "$Env:SystemDrive\Apps\Zoom\Meetings" 22 | New-Item -Path $Path -ItemType "Directory" -Force -ErrorAction "SilentlyContinue" | Out-Null 23 | 24 | # Import shared functions written to disk by 000_PrepImage.ps1 25 | $FunctionFile = "$Env:TEMP\NerdioFunctions.psm1" 26 | Import-Module -Name $FunctionFile -Force -ErrorAction "Stop" 27 | Write-LogFile -Message "Functions imported from: $FunctionFile" 28 | 29 | # Download Zoom 30 | Write-LogFile -Message "Downloading Zoom Meetings VDI client" 31 | $App = Get-EvergreenApp -Name "ZoomVDI" | Where-Object { $_.Platform -eq "VDIClient" -and $_.Architecture -eq "x64" } | Select-Object -First 1 32 | Write-LogFile -Message "Downloading Zoom Meetings VDI client version $($App.Version) to $Path" 33 | $OutFile = Save-EvergreenApp -InputObject $App -CustomPath $Path -ErrorAction "Stop" 34 | 35 | $LogPath = (Get-LogFile).Path 36 | $LogFile = "$LogPath\ZoomMeetings$($App.Version).log" -replace " ", "" 37 | $params = @{ 38 | FilePath = "$Env:SystemRoot\System32\msiexec.exe" 39 | ArgumentList = "/package `"$($OutFile.FullName)`" zSilentStart=false zNoDesktopShortCut=true ALLUSERS=1 /quiet /log $LogFile" 40 | } 41 | Start-ProcessWithLog @params 42 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/Teams/Uninstall.ps1: -------------------------------------------------------------------------------- 1 | # Variables 2 | [System.String] $PackageFamilyName = "MSTeams_8wekyb3d8bbwe" 3 | 4 | function Get-InstalledSoftware { 5 | $PropertyNames = "DisplayName", "DisplayVersion", "Publisher", "UninstallString", "PSPath", "WindowsInstaller", 6 | "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize", "SystemComponent" 7 | ("HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", 8 | "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*") | ` 9 | ForEach-Object { 10 | Get-ItemProperty -Path $_ -Name $PropertyNames -ErrorAction "SilentlyContinue" | ` 11 | . { process { if ($null -ne $_.DisplayName) { $_ } } } | ` 12 | Where-Object { $_.SystemComponent -ne 1 } | ` 13 | Select-Object -Property @{n = "Name"; e = { $_.DisplayName } }, @{n = "Version"; e = { $_.DisplayVersion } }, "Publisher", 14 | "UninstallString", @{n = "RegistryPath"; e = { $_.PSPath -replace "Microsoft.PowerShell.Core\\Registry::", "" } }, 15 | "PSChildName", "WindowsInstaller", "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize" | ` 16 | Sort-Object -Property "Name", "Publisher" 17 | } 18 | } 19 | 20 | Get-InstalledSoftware | Where-Object { $_.Name -match "Microsoft Teams Meeting Add-in*" } | ForEach-Object { 21 | $Context.Log("Uninstalling Windows Installer: $($_.PSChildName)") 22 | $params = @{ 23 | FilePath = "$Env:SystemRoot\System32\msiexec.exe" 24 | ArgumentList = "/uninstall `"$($_.PSChildName)`" /quiet /norestart" 25 | Wait = $true 26 | PassThru = $true 27 | NoNewWindow = $true 28 | ErrorAction = "Stop" 29 | } 30 | $result = Start-Process @params 31 | $Context.Log("Uninstall complete. Return code: $($result.ExitCode)") 32 | } 33 | 34 | Get-AppxPackage -AllUsers | Where-Object { $_.PackageFamilyName -eq $PackageFamilyName } | ForEach-Object { 35 | $Context.Log("Removing existing AppX package: $($_.Name)") 36 | $_ | Remove-AppxPackage -AllUsers -ErrorAction "Stop" 37 | } 38 | Start-Sleep -Seconds 10 39 | $Context.Log("Uninstall complete") 40 | -------------------------------------------------------------------------------- /actions/core/103_MicrosoftNET.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Installs the Microsoft .NET Desktop LTS and Current Runtimes. 4 | 5 | .DESCRIPTION 6 | This script installs the Microsoft .NET Desktop LTS (Long-Term Support) and Current Runtimes. 7 | It uses the Evergreen module to download the appropriate installer and installs it silently with the specified command-line arguments. 8 | 9 | .PARAMETER Path 10 | The path where the Microsoft .NET runtime will be downloaded. The default path is "$Env:SystemDrive\Apps\Microsoft\NET". 11 | 12 | .EXAMPLE 13 | .\103_MicrosoftNET.ps1 14 | Installs the Microsoft .NET Desktop LTS and Current Runtimes using the default installation path. 15 | 16 | .NOTES 17 | - This script requires the Evergreen module to be installed. 18 | - The script creates a log file at "$Env:SystemRoot\Logs\ImageBuild\Microsoft.NET.log" to capture installation logs. 19 | #> 20 | 21 | #description: Installs the Microsoft .NET Desktop LTS 22 | #execution mode: Combined 23 | #tags: Evergreen, Microsoft, .NET 24 | #Requires -Modules Evergreen 25 | [System.String] $Path = "$Env:SystemDrive\Apps\Microsoft\NET" 26 | New-Item -Path $Path -ItemType "Directory" -Force -ErrorAction "SilentlyContinue" | Out-Null 27 | 28 | # Import shared functions written to disk by 000_PrepImage.ps1 29 | $FunctionFile = "$Env:TEMP\NerdioFunctions.psm1" 30 | Import-Module -Name $FunctionFile -Force -ErrorAction "Stop" 31 | Write-LogFile -Message "Functions imported from: $FunctionFile" 32 | 33 | #region Script logic 34 | # Download 35 | 36 | $App = Get-EvergreenApp -Name "Microsoft.NET" | ` 37 | Where-Object { $_.Installer -eq "windowsdesktop" -and $_.Architecture -eq "x64" -and $_.Channel -match "LTS" } 38 | $OutFile = Save-EvergreenApp -InputObject $App -CustomPath $Path -ErrorAction "Stop" 39 | 40 | $LogPath = (Get-LogFile).Path 41 | foreach ($File in $OutFile) { 42 | $LogFile = "$LogPath\Microsoft.NET.log" -replace " ", "" 43 | Write-LogFile -Message "Installing Microsoft .NET Desktop LTS" 44 | $params = @{ 45 | FilePath = $File.FullName 46 | ArgumentList = "/install /quiet /norestart /log $LogFile" 47 | } 48 | Start-ProcessWithLog @params 49 | } 50 | #endregion 51 | -------------------------------------------------------------------------------- /actions/3rdparty/411_draw.io.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Installs the latest version of draw.io. 4 | 5 | .DESCRIPTION 6 | This script installs the latest version of draw.io using the Evergreen module. 7 | It creates a directory for draw.io, imports the Evergreen module, retrieves the latest version of the diagrams.net MSI package, 8 | saves it to the draw.io directory, and then installs draw.io silently using msiexec.exe. 9 | 10 | .PARAMETER Path 11 | The path where draw.io will be downloaded. The default path is "$Env:SystemDrive\Apps\draw.io". 12 | 13 | .NOTES 14 | - This script requires the Evergreen module to be installed. 15 | - The script will create a log file in "$Env:SystemRoot\Logs\ImageBuild" to track the installation progress. 16 | - The script will remove the draw.io shortcut from the desktop after installation. 17 | #> 18 | 19 | #description: Installs the latest draw.io 20 | #execution mode: Combined 21 | #tags: Evergreen, draw.io 22 | #Requires -Modules Evergreen 23 | [System.String] $Path = "$Env:SystemDrive\Apps\drawio" 24 | New-Item -Path $Path -ItemType "Directory" -Force -ErrorAction "SilentlyContinue" | Out-Null 25 | 26 | # Import shared functions written to disk by 000_PrepImage.ps1 27 | $FunctionFile = "$Env:TEMP\NerdioFunctions.psm1" 28 | Import-Module -Name $FunctionFile -Force -ErrorAction "Stop" 29 | Write-LogFile -Message "Functions imported from: $FunctionFile" 30 | 31 | 32 | Write-LogFile -Message "Query Evergreen for JGraphDrawIO MSI" 33 | $App = Get-EvergreenApp -Name "JGraphDrawIO" | Where-Object { $_.Type -eq "msi" } | Select-Object -First 1 34 | Write-LogFile -Message "Downloading draw.io version $($App.Version) to $Path" 35 | $OutFile = Save-EvergreenApp -InputObject $App -CustomPath $Path -ErrorAction "Stop" 36 | 37 | $LogPath = (Get-LogFile).Path 38 | $LogFile = "$LogPath\drawio$($App.Version).log" -replace " ", "" 39 | $params = @{ 40 | FilePath = "$Env:SystemRoot\System32\msiexec.exe" 41 | ArgumentList = "/package `"$($OutFile.FullName)`" ALLUSERS=1 /quiet /log $LogFile" 42 | } 43 | Start-ProcessWithLog @params 44 | 45 | Start-Sleep -Seconds 5 46 | $Shortcuts = @("$Env:Public\Desktop\draw.io.lnk") 47 | Remove-Item -Path $Shortcuts -Force -ErrorAction "Ignore" 48 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/VisualStudioCode/Uninstall.ps1: -------------------------------------------------------------------------------- 1 | function Get-InstalledSoftware { 2 | $PropertyNames = "DisplayName", "DisplayVersion", "Publisher", "UninstallString", "PSPath", "WindowsInstaller", 3 | "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize", "SystemComponent" 4 | ("HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", 5 | "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*") | ` 6 | ForEach-Object { 7 | Get-ItemProperty -Path $_ -Name $PropertyNames -ErrorAction "SilentlyContinue" | ` 8 | . { process { if ($null -ne $_.DisplayName) { $_ } } } | ` 9 | Where-Object { $_.SystemComponent -ne 1 } | ` 10 | Select-Object -Property @{n = "Name"; e = { $_.DisplayName } }, @{n = "Version"; e = { $_.DisplayVersion } }, "Publisher", 11 | "UninstallString", @{n = "RegistryPath"; e = { $_.PSPath -replace "Microsoft.PowerShell.Core\\Registry::", "" } }, 12 | "PSChildName", "WindowsInstaller", "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize" | ` 13 | Sort-Object -Property "Name", "Publisher" 14 | } 15 | } 16 | 17 | Get-InstalledSoftware | Where-Object { $_.Name -match "Microsoft Visual Studio Code*" } | ForEach-Object { 18 | if ($_.UninstallString -match '"([^"]+)"') { 19 | $Context.Log("Uninstall with: $($Matches[1])") 20 | $params = @{ 21 | FilePath = $Matches[1] 22 | ArgumentList = "/VERYSILENT /NORESTART" 23 | Wait = $true 24 | PassThru = $true 25 | NoNewWindow = $true 26 | ErrorAction = "Stop" 27 | } 28 | $result = Start-Process @params 29 | $Context.Log("Uninstall complete. Return code: $($result.ExitCode)") 30 | } 31 | else { 32 | $Context.Log("Failed to parse UninstallString") 33 | } 34 | } 35 | 36 | # Remove shortcuts 37 | $Shortcuts = @("$Env:ProgramData\Microsoft\Windows\Start Menu\Programs\Visual Studio Code\Visual Studio Code.lnk") 38 | Get-Item -Path $Shortcuts -ErrorAction "SilentlyContinue" | ` 39 | ForEach-Object { $Context.Log("Remove file: $($_.FullName)"); Remove-Item -Path $_.FullName -Force -ErrorAction "SilentlyContinue" } 40 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/SQLServerManagementStudio/Uninstall.ps1: -------------------------------------------------------------------------------- 1 | function Get-InstalledSoftware { 2 | $PropertyNames = "DisplayName", "DisplayVersion", "Publisher", "UninstallString", "PSPath", "WindowsInstaller", 3 | "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize", "SystemComponent" 4 | ("HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", 5 | "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*") | ` 6 | ForEach-Object { 7 | Get-ItemProperty -Path $_ -Name $PropertyNames -ErrorAction "SilentlyContinue" | ` 8 | . { process { if ($null -ne $_.DisplayName) { $_ } } } | ` 9 | Where-Object { $_.SystemComponent -ne 1 } | ` 10 | Select-Object -Property @{n = "Name"; e = { $_.DisplayName } }, @{n = "Version"; e = { $_.DisplayVersion } }, "Publisher", 11 | "UninstallString", @{n = "RegistryPath"; e = { $_.PSPath -replace "Microsoft.PowerShell.Core\\Registry::", "" } }, 12 | "PSChildName", "WindowsInstaller", "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize" | ` 13 | Sort-Object -Property "Name", "Publisher" 14 | } 15 | } 16 | 17 | Get-InstalledSoftware | Where-Object { $_.Name -match "Microsoft SQL Server Management Studio*" } | ForEach-Object { 18 | if ($_.UninstallString -match '"([^"]+)"') { 19 | $Context.Log("Uninstall with: $($Matches[1])") 20 | $params = @{ 21 | FilePath = $Matches[1] 22 | ArgumentList = "/uninstall /allusers /quiet /norestart" 23 | Wait = $true 24 | PassThru = $true 25 | NoNewWindow = $true 26 | ErrorAction = "Stop" 27 | } 28 | $result = Start-Process @params 29 | $Context.Log("Uninstall complete. Return code: $($result.ExitCode)") 30 | } 31 | else { 32 | $Context.Log("Failed to parse UninstallString") 33 | } 34 | } 35 | 36 | # Remove shortcuts 37 | $Shortcuts = @("$Env:ProgramData\Microsoft\Windows\Start Menu\Programs\Microsoft SQL Server Tools 20") 38 | Get-Item -Path $Shortcuts -ErrorAction "SilentlyContinue" | ` 39 | ForEach-Object { $Context.Log("Remove file: $($_.FullName)"); Remove-Item -Path $_.FullName -Force -ErrorAction "SilentlyContinue" } 40 | -------------------------------------------------------------------------------- /actions/core/214_MicrosoftAzureCLI.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Installs the latest Microsoft Azure CLI. 4 | 5 | .DESCRIPTION 6 | This script installs the latest version of Microsoft Azure CLI on the local machine. 7 | It uses the Evergreen module to download and install the MSI package for Microsoft Azure CLI. 8 | The installation is performed silently without any user interaction. 9 | 10 | .PARAMETER Path 11 | Specifies the download path for Microsoft Azure CLI. The default path is "$Env:SystemDrive\Apps\Microsoft\AzureCli". 12 | 13 | .NOTES 14 | - This script requires the Evergreen module to be installed. 15 | - The script creates a log file in "$Env:SystemRoot\Logs\ImageBuild" directory to track the installation progress and any errors that occur during the installation. 16 | - The script uses the Start-Process cmdlet to execute the MSI package installation silently. 17 | #> 18 | 19 | #description: Installs the latest Microsoft Azure CLI 20 | #execution mode: Combined 21 | #tags: Evergreen, Microsoft, Azure 22 | #Requires -Modules Evergreen 23 | [System.String] $Path = "$Env:SystemDrive\Apps\Microsoft\AzureCli" 24 | New-Item -Path $Path -ItemType "Directory" -Force -ErrorAction "SilentlyContinue" | Out-Null 25 | 26 | # Import shared functions written to disk by 000_PrepImage.ps1 27 | $FunctionFile = "$Env:TEMP\NerdioFunctions.psm1" 28 | Import-Module -Name $FunctionFile -Force -ErrorAction "Stop" 29 | Write-LogFile -Message "Functions imported from: $FunctionFile" 30 | 31 | #region Script logic 32 | 33 | $App = Get-EvergreenApp -Name "MicrosoftAzureCLI" | ` 34 | Where-Object { $_.Type -eq "msi" } | Select-Object -First 1 35 | $OutFile = Save-EvergreenApp -InputObject $App -CustomPath $Path -ErrorAction "Stop" 36 | Write-LogFile -Message "Microsoft Azure CLI $($App.Version) downloaded to: $($OutFile.FullName)" 37 | 38 | $LogPath = (Get-LogFile).Path 39 | $LogFile = "$LogPath\MicrosoftAvdCli$($App.Version).log" -replace " ", "" 40 | Write-LogFile -Message "Starting Microsoft Azure CLI installation from: $($OutFile.FullName)" 41 | $params = @{ 42 | FilePath = "$Env:SystemRoot\System32\msiexec.exe" 43 | ArgumentList = "/package `"$($OutFile.FullName)`" /quiet /norestart ALLUSERS=1 /log $LogFile" 44 | } 45 | Start-ProcessWithLog @params 46 | #endregion 47 | -------------------------------------------------------------------------------- /actions/3rdparty/408_RemoteDesktopAnalyzer.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Downloads the Remote Display Analyzer and Connection Experience Indicator to 'C:\Program Files\RemoteDisplayAnalyzer'. 4 | 5 | .DESCRIPTION 6 | This script downloads the Remote Display Analyzer and Connection Experience Indicator tools to the specified path. 7 | It creates the necessary directories and imports the required module before downloading the tools. 8 | 9 | .PARAMETER Path 10 | Specifies the path where the tools will be downloaded. The default path is 'C:\Program Files\RemoteDisplayAnalyzer'. 11 | 12 | .NOTES 13 | - This script requires the "Evergreen" module to be installed. 14 | - The script may require administrative privileges to create directories and download the tools. 15 | - The script may display warnings if the tools are already installed or if there are any issues during the download process. 16 | #> 17 | 18 | #description: Downloads the Remote Display Analyzer and Connection Experience Indicator 19 | #execution mode: Combined 20 | #tags: Evergreen, Remote Display Analyzer, Tools 21 | #Requires -Modules Evergreen 22 | [System.String] $Path = "$Env:ProgramFiles\RemoteDisplayAnalyzer" 23 | New-Item -Path $Path -ItemType "Directory" -Force -ErrorAction "SilentlyContinue" | Out-Null 24 | 25 | # Import shared functions written to disk by 000_PrepImage.ps1 26 | $FunctionFile = "$Env:TEMP\NerdioFunctions.psm1" 27 | Import-Module -Name $FunctionFile -Force -ErrorAction "Stop" 28 | Write-LogFile -Message "Functions imported from: $FunctionFile" 29 | 30 | Write-LogFile -Message "Query Evergreen for Remote Display Analyzer and Connection Experience Indicator" 31 | $App = Get-EvergreenApp -Name "RDAnalyzer" | Select-Object -First 1 32 | Write-LogFile -Message "Downloading Remote Display Analyzer version $($App.Version) to $Path" 33 | Save-EvergreenApp -InputObject $App -CustomPath $Path -Force -ErrorAction "Stop" | Out-Null 34 | 35 | Write-LogFile -Message "Query Evergreen for Connection Experience Indicator" 36 | $App = Get-EvergreenApp -Name "ConnectionExperienceIndicator" | Select-Object -First 1 37 | Write-LogFile -Message "Downloading Connection Experience Indicator version $($App.Version) to $Path" 38 | Save-EvergreenApp -InputObject $App -CustomPath $Path -Force -ErrorAction "Stop" | Out-Null 39 | -------------------------------------------------------------------------------- /actions/core/215_MicrosoftPowerShell.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Installs the latest Microsoft PowerShell. 4 | 5 | .DESCRIPTION 6 | This script installs the latest version of Microsoft PowerShell. It uses the Evergreen module to retrieve the latest stable release of PowerShell and installs it silently. The installation log is saved in the Nerdio Logs directory. 7 | 8 | .PARAMETER Path 9 | The installation path for Microsoft PowerShell. The default path is "$Env:SystemDrive\Apps\Microsoft\PowerShell". 10 | 11 | .EXAMPLE 12 | .\215_MicrosoftPowerShell.ps1 13 | 14 | This example runs the script to install the latest Microsoft PowerShell. 15 | 16 | .NOTES 17 | - Requires the Evergreen module. 18 | - Only installs the x64 architecture of Microsoft PowerShell. 19 | - The installation log is saved in "$Env:SystemRoot\Logs\ImageBuild". 20 | #> 21 | 22 | #description: Installs the latest Microsoft PowerShell 23 | #execution mode: Combined 24 | #tags: Evergreen, Microsoft, PowerShell 25 | #Requires -Modules Evergreen 26 | [System.String] $Path = "$Env:SystemDrive\Apps\Microsoft\PowerShell" 27 | New-Item -Path $Path -ItemType "Directory" -Force -ErrorAction "SilentlyContinue" | Out-Null 28 | 29 | # Import shared functions written to disk by 000_PrepImage.ps1 30 | $FunctionFile = "$Env:TEMP\NerdioFunctions.psm1" 31 | Import-Module -Name $FunctionFile -Force -ErrorAction "Stop" 32 | Write-LogFile -Message "Functions imported from: $FunctionFile" 33 | 34 | #region Script logic 35 | 36 | $App = Get-EvergreenApp -Name "MicrosoftPowerShell" | ` 37 | Where-Object { $_.Architecture -eq "x64" -and $_.Release -eq "Stable" } | ` 38 | Select-Object -First 1 39 | $OutFile = Save-EvergreenApp -InputObject $App -CustomPath $Path -ErrorAction "Stop" 40 | Write-LogFile -Message "Microsoft PowerShell $($App.Version) downloaded to: $($OutFile.FullName)" 41 | 42 | $LogFile = "$Env:SystemRoot\Logs\ImageBuild\MicrosoftPowerShell$($App.Version).log" -replace " ", "" 43 | Write-LogFile -Message "Starting Microsoft PowerShell installation from: $($OutFile.FullName)" 44 | $params = @{ 45 | FilePath = "$Env:SystemRoot\System32\msiexec.exe" 46 | ArgumentList = "/package `"$($OutFile.FullName)`" /quiet /norestart ALLUSERS=1 /log $LogFile" 47 | } 48 | Start-ProcessWithLog @params 49 | #endregion 50 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.toptal.com/developers/gitignore/api/macos,powershell,windows 2 | # Edit at https://www.toptal.com/developers/gitignore?templates=macos,powershell,windows 3 | 4 | ### macOS ### 5 | # General 6 | .DS_Store 7 | .AppleDouble 8 | .LSOverride 9 | 10 | # Icon must end with two \r 11 | Icon 12 | 13 | 14 | # Thumbnails 15 | ._* 16 | 17 | # Files that might appear in the root of a volume 18 | .DocumentRevisions-V100 19 | .fseventsd 20 | .Spotlight-V100 21 | .TemporaryItems 22 | .Trashes 23 | .VolumeIcon.icns 24 | .com.apple.timemachine.donotpresent 25 | 26 | # Directories potentially created on remote AFP share 27 | .AppleDB 28 | .AppleDesktop 29 | Network Trash Folder 30 | Temporary Items 31 | .apdisk 32 | 33 | ### macOS Patch ### 34 | # iCloud generated files 35 | *.icloud 36 | 37 | ### PowerShell ### 38 | # Exclude packaged modules 39 | *.zip 40 | 41 | # Exclude .NET assemblies from source 42 | *.dll 43 | 44 | ### Windows ### 45 | # Windows thumbnail cache files 46 | Thumbs.db 47 | Thumbs.db:encryptable 48 | ehthumbs.db 49 | ehthumbs_vista.db 50 | 51 | # Dump file 52 | *.stackdump 53 | 54 | # Folder config file 55 | [Dd]esktop.ini 56 | 57 | # Recycle Bin used on file shares 58 | $RECYCLE.BIN/ 59 | 60 | # Windows Installer files 61 | *.cab 62 | *.msi 63 | *.msix 64 | *.msm 65 | *.msp 66 | 67 | # Windows shortcuts 68 | *.lnk 69 | 70 | # Others 71 | NerdioManagerVariables.json 72 | creds.json 73 | environment.json 74 | 75 | ## Terraform 76 | .terraform.lock.hcl 77 | *.tfplan 78 | 79 | # Local .terraform directories 80 | **/.terraform/* 81 | 82 | # .tfstate files 83 | *.tfstate 84 | *.tfstate.* 85 | 86 | # Crash log files 87 | crash.log 88 | crash.*.log 89 | 90 | # Exclude all .tfvars files, which are likely to contain sensitive data 91 | *.tfvars 92 | *.tfvars.json 93 | 94 | # Ignore override files as they are usually used to override resources locally 95 | override.tf 96 | override.tf.json 97 | *_override.tf 98 | *_override.tf.json 99 | 100 | # Ignore CLI configuration files 101 | .terraformrc 102 | terraform.rc 103 | 104 | # Ignore lock files (optional - remove if you want to commit these) 105 | # .terraform.lock.hcl 106 | 107 | # NME artifacts 108 | nme/artifacts/** 109 | nme/terraform-sf/** 110 | -------------------------------------------------------------------------------- /actions/tools/Install-MicrosoftAzurePipelinesAgent.ps1: -------------------------------------------------------------------------------- 1 | #description: Installs the Microsoft Azure Pipelines agent to enable automated testing via Azure Pipelines. Do not run on production session hosts. 2 | #execution mode: Combined 3 | #tags: Evergreen, Testing, DevOps 4 | #Requires -Modules Evergreen 5 | [System.String] $Path = "$Env:SystemDrive\agents" 6 | 7 | # Check that the required variables have been set in Nerdio Manager 8 | foreach ($Value in "DevOpsUrl", "DevOpsPat", "DevOpsPool", "DevOpsUser", "DevOpsPassword") { 9 | if ($null -eq $SecureVars.$Value) { throw "$Value is $null" } 10 | } 11 | 12 | #region Script logic 13 | New-Item -Path $Path -ItemType "Directory" -Force -ErrorAction "SilentlyContinue" | Out-Null 14 | 15 | # Download 16 | 17 | $App = Get-EvergreenApp -Name "MicrosoftAzurePipelinesAgent" | ` 18 | Where-Object { $_.Architecture -eq "x64" } | ` 19 | Select-Object -First 1 20 | $OutFile = Save-EvergreenApp -InputObject $App -CustomPath $Env:Temp -WarningAction "SilentlyContinue" 21 | 22 | # Create the local account that the DevOps Pipelines agent service will run under 23 | $params = @{ 24 | Name = $SecureVars.DevOpsUser 25 | Password = (ConvertTo-SecureString -String $SecureVars.DevOpsPassword -AsPlainText -Force) 26 | Description = "Azure Pipelines agent service for elevated exec." 27 | UserMayNotChangePassword = $true 28 | Confirm = $false 29 | } 30 | New-LocalUser @params 31 | Add-LocalGroupMember -Group "Administrators" -Member $SecureVars.DevOpsUser 32 | 33 | Expand-Archive -Path $OutFile.FullName -DestinationPath $Path -Force 34 | Push-Location -Path $Path 35 | 36 | # Agent install options 37 | $Options = "--unattended 38 | --url `"$($SecureVars.DevOpsUrl)`" 39 | --auth pat 40 | --token `"$($SecureVars.DevOpsPat)`" 41 | --pool `"$($SecureVars.DevOpsPool)`" 42 | --agent $Env:COMPUTERNAME 43 | --runAsService 44 | --windowsLogonAccount `"$($SecureVars.DevOpsUser)`" 45 | --windowsLogonPassword `"$($SecureVars.DevOpsPassword)`" 46 | --replace" 47 | $params = @{ 48 | FilePath = "$Path\config.cmd" 49 | ArgumentList = $($Options -replace "\s+", " ") 50 | Wait = $true 51 | NoNewWindow = $true 52 | PassThru = $true 53 | } 54 | Start-Process @params 55 | #endregion 56 | -------------------------------------------------------------------------------- /shell-apps/Microsoft/EdgeWebView2/Uninstall.ps1: -------------------------------------------------------------------------------- 1 | function Get-InstalledSoftware { 2 | $PropertyNames = "DisplayName", "DisplayVersion", "Publisher", "UninstallString", "PSPath", "WindowsInstaller", 3 | "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize", "SystemComponent" 4 | ("HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", 5 | "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*") | ` 6 | ForEach-Object { 7 | Get-ItemProperty -Path $_ -Name $PropertyNames -ErrorAction "SilentlyContinue" | ` 8 | . { process { if ($null -ne $_.DisplayName) { $_ } } } | ` 9 | Select-Object -Property @{n = "Name"; e = { $_.DisplayName } }, @{n = "Version"; e = { $_.DisplayVersion } }, "Publisher", 10 | "UninstallString", @{n = "RegistryPath"; e = { $_.PSPath -replace "Microsoft.PowerShell.Core\\Registry::", "" } }, 11 | "PSChildName", "WindowsInstaller", "InstallDate", "InstallSource", "HelpLink", "Language", "EstimatedSize" | ` 12 | Sort-Object -Property "Name", "Publisher" 13 | } 14 | } 15 | 16 | function ConvertTo-UninstallCommand { 17 | [CmdletBinding()] 18 | param ( 19 | [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] 20 | [System.String]$UninstallString 21 | ) 22 | begin { 23 | $regex = '(?i)"?([A-Z]:\\[^"]*?\.exe|[A-Za-z0-9._-]+\.exe)"?\s*((?:\S+\s*)*)' 24 | } 25 | process { 26 | if ($UninstallString -match $regex) { 27 | $Exe = $Matches[1] 28 | $Arguments = $Matches[2] 29 | [PSCustomObject]@{ 30 | FilePath = if ($Exe -match "msiexec.exe") { "$Env:SystemRoot\System32\msiexec.exe" } else { $Exe } 31 | ArgumentList = ($Arguments -replace '\s+', ' ').Trim() 32 | } 33 | } 34 | else { 35 | return $null 36 | } 37 | } 38 | } 39 | 40 | $Uninstall = Get-InstalledSoftware | Where-Object { $_.Name -match "Microsoft Edge WebView2 Runtime" } | ConvertTo-UninstallCommand 41 | $params = @{ 42 | FilePath = $Uninstall.FilePath 43 | ArgumentList = "$($Uninstall.ArgumentList) --force-uninstall" 44 | Wait = $true 45 | PassThru = $true 46 | NoNewWindow = $true 47 | ErrorAction = "Stop" 48 | } 49 | $result = Start-Process @params 50 | $Context.Log("Uninstall complete. Return code: $($result.ExitCode)") 51 | -------------------------------------------------------------------------------- /actions/3rdparty/404_NotepadPlusPlus.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Installs the latest Notepad++ 64-bit with automatic updates disabled. 4 | 5 | .DESCRIPTION 6 | This script installs the latest version of Notepad++ 64-bit on the local machine. It also disables the automatic update feature of Notepad++. 7 | 8 | .PARAMETER Path 9 | Specifies the download path for Notepad++. The default path is "$Env:SystemDrive\Apps\NotepadPlusPlus". 10 | 11 | .NOTES 12 | - This script requires the "Evergreen" module. 13 | - The script will create a directory at the specified installation path if it does not already exist. 14 | - The script will create a directory at "$Env:SystemRoot\Logs\ImageBuild" if it does not already exist. 15 | - The script will download the latest version of Notepad++ from the Evergreen repository and install it silently. 16 | - The script will disable the automatic update feature of Notepad++ by renaming the updater folder. 17 | #> 18 | 19 | #description: Installs the latest Notepad++ 64-bit 20 | #execution mode: Combined 21 | #tags: Evergreen, Notepad++ 22 | #Requires -Modules Evergreen 23 | [System.String] $Path = "$Env:SystemDrive\NotepadPlusPlus" 24 | New-Item -Path $Path -ItemType "Directory" -Force -ErrorAction "SilentlyContinue" | Out-Null 25 | 26 | # Import shared functions written to disk by 000_PrepImage.ps1 27 | $FunctionFile = "$Env:TEMP\NerdioFunctions.psm1" 28 | Import-Module -Name $FunctionFile -Force -ErrorAction "Stop" 29 | Write-LogFile -Message "Functions imported from: $FunctionFile" 30 | 31 | Write-LogFile -Message "Query Evergreen for Notepad++ x64" 32 | $App = Get-EvergreenApp -Name "NotepadPlusPlus" | Where-Object { $_.Architecture -eq "x64" -and $_.Type -eq "exe" } | Select-Object -First 1 33 | Write-LogFile -Message "Downloading Notepad++ version $($App.Version) to $Path" 34 | $OutFile = Save-EvergreenApp -InputObject $App -CustomPath $Path -ErrorAction "Stop" 35 | 36 | $params = @{ 37 | FilePath = $OutFile.FullName 38 | ArgumentList = "/S" 39 | } 40 | Start-ProcessWithLog @params 41 | 42 | # Disable updater 43 | $UpdaterPath = "$Env:ProgramFiles\Notepad++\updater" 44 | $RenamePath = "$Env:ProgramFiles\Notepad++\updater.disabled" 45 | if (Test-Path -Path $UpdaterPath) { 46 | if (Test-Path -Path $RenamePath) { 47 | Remove-Item -Path $RenamePath -Recurse -Force -ErrorAction "SilentlyContinue" 48 | } 49 | Rename-Item -Path $UpdaterPath -NewName "updater.disabled" -Force -ErrorAction "SilentlyContinue" 50 | } 51 | -------------------------------------------------------------------------------- /actions/core/212_MicrosoftSQLServerManagementStudio.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Installs the latest Microsoft SQL Server Management Studio. 4 | 5 | .DESCRIPTION 6 | This script installs the latest version of Microsoft SQL Server Management Studio (SSMS) on the local machine. 7 | It utilizes the Evergreen module to download and install the specified version of SSMS. 8 | 9 | .PARAMETER Path 10 | Specifies the download path for SSMS. The default path is "$Env:SystemDrive\Apps\Microsoft\Ssms". 11 | 12 | .NOTES 13 | - This script requires the Evergreen module to be installed. 14 | - The script creates a log file in "$Env:SystemRoot\Logs\ImageBuild" to track the installation progress. 15 | - The script supports multiple languages, but it only installs the English version of SSMS. 16 | - The installation is performed silently without any user interaction. 17 | - The script checks if SSMS is already installed and skips the installation if it is. 18 | - The exit code of the installation process is logged for reference. 19 | #> 20 | 21 | #description: Installs the latest Microsoft SQL Server Management Studio 22 | #execution mode: Combined 23 | #tags: Evergreen, Microsoft, SQL Server 24 | #Requires -Modules Evergreen 25 | [System.String] $Path = "$Env:SystemDrive\Apps\Microsoft\Ssms" 26 | New-Item -Path $Path -ItemType "Directory" -Force -ErrorAction "SilentlyContinue" | Out-Null 27 | 28 | # Import shared functions written to disk by 000_PrepImage.ps1 29 | $FunctionFile = "$Env:TEMP\NerdioFunctions.psm1" 30 | Import-Module -Name $FunctionFile -Force -ErrorAction "Stop" 31 | Write-LogFile -Message "Functions imported from: $FunctionFile" 32 | 33 | #region Script logic 34 | 35 | $App = Get-EvergreenApp -Name "MicrosoftSsms" | ` 36 | Where-Object { $_.Language -eq "English" } | Select-Object -First 1 37 | $OutFile = Save-EvergreenApp -InputObject $App -CustomPath $Path -ErrorAction "Stop" 38 | Write-LogFile -Message "Microsoft SQL Server Management Studio $($App.Version) downloaded to: $($OutFile.FullName)" 39 | 40 | $LogPath = (Get-LogFile).Path 41 | $LogFile = "$LogPath\MicrosoftSQLServerManagementStudio$($App.Version).log" -replace " ", "" 42 | Write-LogFile -Message "Starting Microsoft SQL Server Management Studio installation from: $($OutFile.FullName)" 43 | $params = @{ 44 | FilePath = $OutFile.FullName 45 | ArgumentList = "/install /quiet /norestart DoNotInstallAzureDataStudio=1 /log $LogFile" 46 | } 47 | Start-ProcessWithLog @params 48 | #endregion 49 | --------------------------------------------------------------------------------