From 502f365566ed44686c11bbea4902fc87023c9452 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 11 Oct 2025 17:04:39 +0000 Subject: [PATCH 1/3] Initial plan From 4ef40f783b0cecd168e8be3636a8d389141565e7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 11 Oct 2025 17:10:25 +0000 Subject: [PATCH 2/3] Add PowerShell scripts for Intune app deployment Co-authored-by: AlwaysLearningTech <37163053+AlwaysLearningTech@users.noreply.github.com> --- .gitignore | 35 ++++ Intune/Examples/Detection-7Zip.ps1 | 32 ++++ Intune/Examples/Detection-GoogleChrome.ps1 | 38 +++++ Intune/Examples/Install-7Zip.ps1 | 100 +++++++++++ Intune/Examples/Install-GoogleChrome.ps1 | 98 +++++++++++ Intune/Examples/Uninstall-7Zip.ps1 | 114 +++++++++++++ Intune/Templates/Detection-Application.ps1 | 170 +++++++++++++++++++ Intune/Templates/Install-Application.ps1 | 159 ++++++++++++++++++ Intune/Templates/Uninstall-Application.ps1 | 185 +++++++++++++++++++++ README.md | 178 +++++++++++++++++++- 10 files changed, 1108 insertions(+), 1 deletion(-) create mode 100644 .gitignore create mode 100644 Intune/Examples/Detection-7Zip.ps1 create mode 100644 Intune/Examples/Detection-GoogleChrome.ps1 create mode 100644 Intune/Examples/Install-7Zip.ps1 create mode 100644 Intune/Examples/Install-GoogleChrome.ps1 create mode 100644 Intune/Examples/Uninstall-7Zip.ps1 create mode 100644 Intune/Templates/Detection-Application.ps1 create mode 100644 Intune/Templates/Install-Application.ps1 create mode 100644 Intune/Templates/Uninstall-Application.ps1 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..93b2d34 --- /dev/null +++ b/.gitignore @@ -0,0 +1,35 @@ +# Windows temp files +Thumbs.db +Desktop.ini +*.tmp +*.temp + +# PowerShell +*.ps1~ +*.psm1~ + +# Log files +*.log + +# Build artifacts +*.intunewin +*.zip + +# IDE and editor files +.vscode/ +.vs/ +*.suo +*.user +.idea/ + +# Mac files +.DS_Store + +# Installer files (should be downloaded separately) +*.msi +*.exe +*.cab + +# Backup files +*.bak +*~ diff --git a/Intune/Examples/Detection-7Zip.ps1 b/Intune/Examples/Detection-7Zip.ps1 new file mode 100644 index 0000000..5e8e149 --- /dev/null +++ b/Intune/Examples/Detection-7Zip.ps1 @@ -0,0 +1,32 @@ +<# +.SYNOPSIS + Detect 7-Zip installation via Intune + +.DESCRIPTION + Detects whether 7-Zip is installed on the system. + +.EXAMPLE + .\Detection-7Zip.ps1 + +.NOTES + Author: KD7DGF + Version: 1.0 + Date: 2025-10-11 +#> + +try { + # Check if 7-Zip is installed + $7zipPath = "C:\Program Files\7-Zip\7z.exe" + + if (Test-Path $7zipPath) { + $version = (Get-Item $7zipPath).VersionInfo.FileVersion + Write-Host "7-Zip detected (Version: $version)" + exit 0 + } else { + # Not detected - exit with 0 but no output + exit 0 + } +} catch { + Write-Error "Detection failed: $($_.Exception.Message)" + exit 1 +} diff --git a/Intune/Examples/Detection-GoogleChrome.ps1 b/Intune/Examples/Detection-GoogleChrome.ps1 new file mode 100644 index 0000000..581134d --- /dev/null +++ b/Intune/Examples/Detection-GoogleChrome.ps1 @@ -0,0 +1,38 @@ +<# +.SYNOPSIS + Detect Google Chrome installation via Intune + +.DESCRIPTION + Detects whether Google Chrome is installed on the system. + +.EXAMPLE + .\Detection-GoogleChrome.ps1 + +.NOTES + Author: KD7DGF + Version: 1.0 + Date: 2025-10-11 +#> + +try { + # Check common installation paths for Chrome + $chromePaths = @( + "C:\Program Files\Google\Chrome\Application\chrome.exe", + "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" + ) + + foreach ($path in $chromePaths) { + if (Test-Path $path) { + $version = (Get-Item $path).VersionInfo.FileVersion + Write-Host "Google Chrome detected (Version: $version)" + exit 0 + } + } + + # Not detected - exit with 0 but no output + exit 0 + +} catch { + Write-Error "Detection failed: $($_.Exception.Message)" + exit 1 +} diff --git a/Intune/Examples/Install-7Zip.ps1 b/Intune/Examples/Install-7Zip.ps1 new file mode 100644 index 0000000..3b184e9 --- /dev/null +++ b/Intune/Examples/Install-7Zip.ps1 @@ -0,0 +1,100 @@ +<# +.SYNOPSIS + Install 7-Zip via Intune + +.DESCRIPTION + Installs 7-Zip MSI package for Windows devices managed by Intune. + +.EXAMPLE + .\Install-7Zip.ps1 + +.NOTES + Author: KD7DGF + Version: 1.0 + Date: 2025-10-11 + + Download the latest 7-Zip MSI from: https://www.7-zip.org/download.html + Place the MSI file in the same directory as this script. +#> + +[CmdletBinding()] +param() + +# Set error action preference +$ErrorActionPreference = "Stop" + +# Configuration +$AppName = "7-Zip" +$InstallerName = "7z*-x64.msi" # Adjust based on actual MSI filename + +# Get script directory +$ScriptPath = Split-Path -Parent -Path $MyInvocation.MyCommand.Definition + +# Logging function +function Write-Log { + param( + [Parameter(Mandatory=$true)] + [string]$Message, + + [Parameter(Mandatory=$false)] + [ValidateSet('Info','Warning','Error')] + [string]$Level = 'Info' + ) + + $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" + $logMessage = "[$timestamp] [$Level] $Message" + + switch ($Level) { + 'Info' { Write-Host $logMessage -ForegroundColor Green } + 'Warning' { Write-Host $logMessage -ForegroundColor Yellow } + 'Error' { Write-Host $logMessage -ForegroundColor Red } + } + + $logPath = "$env:ProgramData\Intune\Logs" + if (-not (Test-Path $logPath)) { + New-Item -Path $logPath -ItemType Directory -Force | Out-Null + } + + $logFile = Join-Path $logPath "Install-7Zip.log" + Add-Content -Path $logFile -Value $logMessage +} + +try { + Write-Log -Message "Starting installation of $AppName" -Level Info + + # Check if running as administrator + $isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) + if (-not $isAdmin) { + Write-Log -Message "Script must be run as administrator" -Level Error + exit 1 + } + + # Find the installer + $installer = Get-ChildItem -Path $ScriptPath -Filter $InstallerName | Select-Object -First 1 + + if (-not $installer) { + Write-Log -Message "7-Zip installer not found in script directory" -Level Error + Write-Log -Message "Expected pattern: $InstallerName" -Level Error + exit 1 + } + + $installerPath = $installer.FullName + Write-Log -Message "Found installer: $installerPath" -Level Info + + # Install 7-Zip + Write-Log -Message "Installing 7-Zip..." -Level Info + $msiArgs = "/i `"$installerPath`" /qn /norestart" + $process = Start-Process -FilePath "msiexec.exe" -ArgumentList $msiArgs -Wait -PassThru + + if ($process.ExitCode -eq 0) { + Write-Log -Message "7-Zip installation completed successfully" -Level Info + exit 0 + } else { + Write-Log -Message "7-Zip installation failed with exit code: $($process.ExitCode)" -Level Error + exit $process.ExitCode + } + +} catch { + Write-Log -Message "Installation failed: $($_.Exception.Message)" -Level Error + exit 1 +} diff --git a/Intune/Examples/Install-GoogleChrome.ps1 b/Intune/Examples/Install-GoogleChrome.ps1 new file mode 100644 index 0000000..704d6d3 --- /dev/null +++ b/Intune/Examples/Install-GoogleChrome.ps1 @@ -0,0 +1,98 @@ +<# +.SYNOPSIS + Install Google Chrome via Intune + +.DESCRIPTION + Installs Google Chrome MSI package for Windows devices managed by Intune. + +.EXAMPLE + .\Install-GoogleChrome.ps1 + +.NOTES + Author: KD7DGF + Version: 1.0 + Date: 2025-10-11 + + Download the Chrome MSI from: https://cloud.google.com/chrome-enterprise/browser/download/ + Place the MSI file in the same directory as this script. +#> + +[CmdletBinding()] +param() + +# Set error action preference +$ErrorActionPreference = "Stop" + +# Configuration +$AppName = "Google Chrome" +$InstallerName = "googlechromestandaloneenterprise64.msi" + +# Get script directory +$ScriptPath = Split-Path -Parent -Path $MyInvocation.MyCommand.Definition + +# Logging function +function Write-Log { + param( + [Parameter(Mandatory=$true)] + [string]$Message, + + [Parameter(Mandatory=$false)] + [ValidateSet('Info','Warning','Error')] + [string]$Level = 'Info' + ) + + $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" + $logMessage = "[$timestamp] [$Level] $Message" + + switch ($Level) { + 'Info' { Write-Host $logMessage -ForegroundColor Green } + 'Warning' { Write-Host $logMessage -ForegroundColor Yellow } + 'Error' { Write-Host $logMessage -ForegroundColor Red } + } + + $logPath = "$env:ProgramData\Intune\Logs" + if (-not (Test-Path $logPath)) { + New-Item -Path $logPath -ItemType Directory -Force | Out-Null + } + + $logFile = Join-Path $logPath "Install-GoogleChrome.log" + Add-Content -Path $logFile -Value $logMessage +} + +try { + Write-Log -Message "Starting installation of $AppName" -Level Info + + # Check if running as administrator + $isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) + if (-not $isAdmin) { + Write-Log -Message "Script must be run as administrator" -Level Error + exit 1 + } + + # Find the installer + $installerPath = Join-Path $ScriptPath $InstallerName + + if (-not (Test-Path $installerPath)) { + Write-Log -Message "Chrome installer not found at: $installerPath" -Level Error + exit 1 + } + + Write-Log -Message "Found installer: $installerPath" -Level Info + + # Install Google Chrome with silent parameters + Write-Log -Message "Installing Google Chrome..." -Level Info + $msiArgs = "/i `"$installerPath`" /qn /norestart" + $process = Start-Process -FilePath "msiexec.exe" -ArgumentList $msiArgs -Wait -PassThru + + if ($process.ExitCode -eq 0) { + Write-Log -Message "Google Chrome installation completed successfully" -Level Info + exit 0 + } else { + Write-Log -Message "Google Chrome installation failed with exit code: $($process.ExitCode)" -Level Error + exit $process.ExitCode + } + +} catch { + Write-Log -Message "Installation failed: $($_.Exception.Message)" -Level Error + exit 1 +} diff --git a/Intune/Examples/Uninstall-7Zip.ps1 b/Intune/Examples/Uninstall-7Zip.ps1 new file mode 100644 index 0000000..6674d13 --- /dev/null +++ b/Intune/Examples/Uninstall-7Zip.ps1 @@ -0,0 +1,114 @@ +<# +.SYNOPSIS + Uninstall 7-Zip via Intune + +.DESCRIPTION + Uninstalls 7-Zip from Windows devices managed by Intune. + +.EXAMPLE + .\Uninstall-7Zip.ps1 + +.NOTES + Author: KD7DGF + Version: 1.0 + Date: 2025-10-11 +#> + +[CmdletBinding()] +param() + +# Set error action preference +$ErrorActionPreference = "Stop" + +# Logging function +function Write-Log { + param( + [Parameter(Mandatory=$true)] + [string]$Message, + + [Parameter(Mandatory=$false)] + [ValidateSet('Info','Warning','Error')] + [string]$Level = 'Info' + ) + + $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" + $logMessage = "[$timestamp] [$Level] $Message" + + switch ($Level) { + 'Info' { Write-Host $logMessage -ForegroundColor Green } + 'Warning' { Write-Host $logMessage -ForegroundColor Yellow } + 'Error' { Write-Host $logMessage -ForegroundColor Red } + } + + $logPath = "$env:ProgramData\Intune\Logs" + if (-not (Test-Path $logPath)) { + New-Item -Path $logPath -ItemType Directory -Force | Out-Null + } + + $logFile = Join-Path $logPath "Uninstall-7Zip.log" + Add-Content -Path $logFile -Value $logMessage +} + +try { + Write-Log -Message "Starting uninstallation of 7-Zip" -Level Info + + # Check if running as administrator + $isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) + if (-not $isAdmin) { + Write-Log -Message "Script must be run as administrator" -Level Error + exit 1 + } + + # Find 7-Zip in installed applications + $registryPaths = @( + "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", + "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*" + ) + + $app = $null + foreach ($path in $registryPaths) { + if (Test-Path $path) { + $app = Get-ItemProperty $path -ErrorAction SilentlyContinue | + Where-Object { $_.DisplayName -like "*7-Zip*" } | + Select-Object -First 1 + + if ($app) { break } + } + } + + if (-not $app) { + Write-Log -Message "7-Zip is not installed" -Level Warning + exit 0 + } + + Write-Log -Message "Found 7-Zip: $($app.DisplayName) - Version: $($app.DisplayVersion)" -Level Info + + if ($app.UninstallString) { + Write-Log -Message "Uninstalling 7-Zip..." -Level Info + + if ($app.UninstallString -like "msiexec*") { + # MSI uninstall + $uninstallArgs = $app.UninstallString -replace "msiexec.exe", "" -replace "/I", "/x" + $uninstallArgs += " /qn /norestart" + $process = Start-Process -FilePath "msiexec.exe" -ArgumentList $uninstallArgs -Wait -PassThru + } else { + # EXE uninstall + $process = Start-Process -FilePath "cmd.exe" -ArgumentList "/c `"$($app.UninstallString)`" /S" -Wait -PassThru + } + + if ($process.ExitCode -eq 0) { + Write-Log -Message "7-Zip uninstallation completed successfully" -Level Info + exit 0 + } else { + Write-Log -Message "7-Zip uninstallation failed with exit code: $($process.ExitCode)" -Level Error + exit $process.ExitCode + } + } else { + Write-Log -Message "No uninstall string found for 7-Zip" -Level Error + exit 1 + } + +} catch { + Write-Log -Message "Uninstallation failed: $($_.Exception.Message)" -Level Error + exit 1 +} diff --git a/Intune/Templates/Detection-Application.ps1 b/Intune/Templates/Detection-Application.ps1 new file mode 100644 index 0000000..19c0264 --- /dev/null +++ b/Intune/Templates/Detection-Application.ps1 @@ -0,0 +1,170 @@ +<# +.SYNOPSIS + Template script for detecting applications via Intune + +.DESCRIPTION + This script provides a template for detecting whether applications are installed. + Intune uses this script to determine the installation state of an application. + + Detection scripts should: + - Exit with code 0 and write output if application is detected + - Exit with code 0 without output if application is not detected + - Exit with code 1 if an error occurs + +.PARAMETER AppName + Name of the application to detect + +.PARAMETER Version + Minimum version required (optional) + +.EXAMPLE + .\Detection-Application.ps1 -AppName "MyApp" -Version "1.0.0" + +.NOTES + Author: KD7DGF + Version: 1.0 + Date: 2025-10-11 +#> + +[CmdletBinding()] +param( + [Parameter(Mandatory=$true)] + [string]$AppName, + + [Parameter(Mandatory=$false)] + [string]$Version, + + [Parameter(Mandatory=$false)] + [string]$InstallPath, + + [Parameter(Mandatory=$false)] + [string]$RegistryPath, + + [Parameter(Mandatory=$false)] + [string]$RegistryValue +) + +# Set error action preference +$ErrorActionPreference = "Stop" + +# Function to search for application in registry +function Get-InstalledApplication { + param( + [Parameter(Mandatory=$true)] + [string]$AppName + ) + + $registryPaths = @( + "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", + "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*", + "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*" + ) + + $installedApps = @() + foreach ($path in $registryPaths) { + if (Test-Path $path) { + $installedApps += Get-ItemProperty $path -ErrorAction SilentlyContinue | + Where-Object { $_.DisplayName -like "*$AppName*" } + } + } + + return $installedApps +} + +# Function to compare versions +function Compare-Version { + param( + [Parameter(Mandatory=$true)] + [string]$InstalledVersion, + + [Parameter(Mandatory=$true)] + [string]$RequiredVersion + ) + + try { + $installed = [Version]$InstalledVersion + $required = [Version]$RequiredVersion + + return $installed -ge $required + } catch { + # If version comparison fails, do string comparison + return $InstalledVersion -ge $RequiredVersion + } +} + +try { + $detected = $false + $detectionMessage = "" + + # Method 1: Check by file path + if ($InstallPath -and (Test-Path $InstallPath)) { + $detected = $true + $detectionMessage = "Application detected at: $InstallPath" + + # If version check is required and it's an executable + if ($Version -and $InstallPath -like "*.exe") { + $fileVersion = (Get-Item $InstallPath).VersionInfo.FileVersion + if ($fileVersion) { + if (Compare-Version -InstalledVersion $fileVersion -RequiredVersion $Version) { + $detectionMessage += " (Version: $fileVersion)" + } else { + $detected = $false + $detectionMessage = "Application found but version $fileVersion is less than required $Version" + } + } + } + } + + # Method 2: Check by registry path + if (-not $detected -and $RegistryPath) { + if (Test-Path $RegistryPath) { + if ($RegistryValue) { + $regValue = Get-ItemProperty -Path $RegistryPath -Name $RegistryValue -ErrorAction SilentlyContinue + if ($regValue) { + $detected = $true + $detectionMessage = "Application detected via registry: $RegistryPath\$RegistryValue" + } + } else { + $detected = $true + $detectionMessage = "Application detected via registry: $RegistryPath" + } + } + } + + # Method 3: Search in installed applications + if (-not $detected) { + $installedApps = Get-InstalledApplication -AppName $AppName + + if ($installedApps.Count -gt 0) { + foreach ($app in $installedApps) { + # Check version if specified + if ($Version -and $app.DisplayVersion) { + if (Compare-Version -InstalledVersion $app.DisplayVersion -RequiredVersion $Version) { + $detected = $true + $detectionMessage = "Application detected: $($app.DisplayName) (Version: $($app.DisplayVersion))" + break + } + } else { + $detected = $true + $versionInfo = if ($app.DisplayVersion) { " (Version: $($app.DisplayVersion))" } else { "" } + $detectionMessage = "Application detected: $($app.DisplayName)$versionInfo" + break + } + } + } + } + + # Output result + if ($detected) { + Write-Host $detectionMessage + exit 0 + } else { + # Application not detected - exit with 0 but no output + exit 0 + } + +} catch { + # Error occurred during detection + Write-Error "Detection failed: $($_.Exception.Message)" + exit 1 +} diff --git a/Intune/Templates/Install-Application.ps1 b/Intune/Templates/Install-Application.ps1 new file mode 100644 index 0000000..949e96e --- /dev/null +++ b/Intune/Templates/Install-Application.ps1 @@ -0,0 +1,159 @@ +<# +.SYNOPSIS + Template script for installing applications via Intune + +.DESCRIPTION + This script provides a template for installing applications through Microsoft Intune. + Modify the installation logic in the main section to match your application requirements. + +.PARAMETER AppName + Name of the application being installed + +.PARAMETER InstallPath + Custom installation path (optional) + +.EXAMPLE + .\Install-Application.ps1 -AppName "MyApp" -InstallPath "C:\Program Files\MyApp" + +.NOTES + Author: KD7DGF + Version: 1.0 + Date: 2025-10-11 +#> + +[CmdletBinding()] +param( + [Parameter(Mandatory=$true)] + [string]$AppName, + + [Parameter(Mandatory=$false)] + [string]$InstallPath, + + [Parameter(Mandatory=$false)] + [string]$InstallerPath, + + [Parameter(Mandatory=$false)] + [string]$Arguments +) + +# Set error action preference +$ErrorActionPreference = "Stop" + +# Logging function +function Write-Log { + param( + [Parameter(Mandatory=$true)] + [string]$Message, + + [Parameter(Mandatory=$false)] + [ValidateSet('Info','Warning','Error')] + [string]$Level = 'Info' + ) + + $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" + $logMessage = "[$timestamp] [$Level] $Message" + + # Log to console + switch ($Level) { + 'Info' { Write-Host $logMessage -ForegroundColor Green } + 'Warning' { Write-Host $logMessage -ForegroundColor Yellow } + 'Error' { Write-Host $logMessage -ForegroundColor Red } + } + + # Log to file + $logPath = "$env:ProgramData\Intune\Logs" + if (-not (Test-Path $logPath)) { + New-Item -Path $logPath -ItemType Directory -Force | Out-Null + } + + $logFile = Join-Path $logPath "Install-$AppName.log" + Add-Content -Path $logFile -Value $logMessage +} + +# Main installation logic +try { + Write-Log -Message "Starting installation of $AppName" -Level Info + + # Check if running as administrator + $isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) + if (-not $isAdmin) { + Write-Log -Message "Script must be run as administrator" -Level Error + exit 1 + } + + # Pre-installation checks + Write-Log -Message "Performing pre-installation checks..." -Level Info + + # Check if application is already installed (modify based on your app) + # Example: Check registry or file existence + + # Installation logic - Customize this section for your application + if ($InstallerPath -and (Test-Path $InstallerPath)) { + Write-Log -Message "Installing from: $InstallerPath" -Level Info + + # Determine installer type and install accordingly + if ($InstallerPath -like "*.msi") { + # MSI installation + $msiArgs = "/i `"$InstallerPath`" /qn /norestart" + if ($Arguments) { + $msiArgs += " $Arguments" + } + Write-Log -Message "Executing: msiexec.exe $msiArgs" -Level Info + $process = Start-Process -FilePath "msiexec.exe" -ArgumentList $msiArgs -Wait -PassThru + + if ($process.ExitCode -eq 0) { + Write-Log -Message "MSI installation completed successfully" -Level Info + } else { + Write-Log -Message "MSI installation failed with exit code: $($process.ExitCode)" -Level Error + exit $process.ExitCode + } + } + elseif ($InstallerPath -like "*.exe") { + # EXE installation + $exeArgs = $Arguments + if (-not $exeArgs) { + $exeArgs = "/S /silent /quiet" # Default silent arguments + } + Write-Log -Message "Executing: $InstallerPath $exeArgs" -Level Info + $process = Start-Process -FilePath $InstallerPath -ArgumentList $exeArgs -Wait -PassThru + + if ($process.ExitCode -eq 0) { + Write-Log -Message "EXE installation completed successfully" -Level Info + } else { + Write-Log -Message "EXE installation failed with exit code: $($process.ExitCode)" -Level Error + exit $process.ExitCode + } + } + else { + Write-Log -Message "Unsupported installer type" -Level Error + exit 1 + } + } + else { + Write-Log -Message "Installer path not provided or does not exist" -Level Warning + Write-Log -Message "Add your custom installation logic here" -Level Info + + # Add your custom installation steps here + # Example: + # Copy-Item -Path "source" -Destination "destination" -Recurse + # New-Item -Path $InstallPath -ItemType Directory -Force + } + + # Post-installation tasks + Write-Log -Message "Performing post-installation tasks..." -Level Info + + # Add any post-installation configurations here + # Examples: + # - Registry modifications + # - Service configurations + # - Shortcuts creation + # - Environment variables + + Write-Log -Message "Installation of $AppName completed successfully" -Level Info + exit 0 + +} catch { + Write-Log -Message "Installation failed: $($_.Exception.Message)" -Level Error + Write-Log -Message "Stack trace: $($_.ScriptStackTrace)" -Level Error + exit 1 +} diff --git a/Intune/Templates/Uninstall-Application.ps1 b/Intune/Templates/Uninstall-Application.ps1 new file mode 100644 index 0000000..ed9bd16 --- /dev/null +++ b/Intune/Templates/Uninstall-Application.ps1 @@ -0,0 +1,185 @@ +<# +.SYNOPSIS + Template script for uninstalling applications via Intune + +.DESCRIPTION + This script provides a template for uninstalling applications through Microsoft Intune. + Modify the uninstallation logic in the main section to match your application requirements. + +.PARAMETER AppName + Name of the application being uninstalled + +.PARAMETER ProductCode + MSI product code (for MSI-based applications) + +.EXAMPLE + .\Uninstall-Application.ps1 -AppName "MyApp" -ProductCode "{12345678-1234-1234-1234-123456789012}" + +.NOTES + Author: KD7DGF + Version: 1.0 + Date: 2025-10-11 +#> + +[CmdletBinding()] +param( + [Parameter(Mandatory=$true)] + [string]$AppName, + + [Parameter(Mandatory=$false)] + [string]$ProductCode, + + [Parameter(Mandatory=$false)] + [string]$UninstallString +) + +# Set error action preference +$ErrorActionPreference = "Stop" + +# Logging function +function Write-Log { + param( + [Parameter(Mandatory=$true)] + [string]$Message, + + [Parameter(Mandatory=$false)] + [ValidateSet('Info','Warning','Error')] + [string]$Level = 'Info' + ) + + $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" + $logMessage = "[$timestamp] [$Level] $Message" + + # Log to console + switch ($Level) { + 'Info' { Write-Host $logMessage -ForegroundColor Green } + 'Warning' { Write-Host $logMessage -ForegroundColor Yellow } + 'Error' { Write-Host $logMessage -ForegroundColor Red } + } + + # Log to file + $logPath = "$env:ProgramData\Intune\Logs" + if (-not (Test-Path $logPath)) { + New-Item -Path $logPath -ItemType Directory -Force | Out-Null + } + + $logFile = Join-Path $logPath "Uninstall-$AppName.log" + Add-Content -Path $logFile -Value $logMessage +} + +# Function to find application in registry +function Get-InstalledApplication { + param( + [Parameter(Mandatory=$true)] + [string]$AppName + ) + + $registryPaths = @( + "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", + "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*" + ) + + $installedApps = @() + foreach ($path in $registryPaths) { + if (Test-Path $path) { + $installedApps += Get-ItemProperty $path -ErrorAction SilentlyContinue | + Where-Object { $_.DisplayName -like "*$AppName*" } + } + } + + return $installedApps +} + +# Main uninstallation logic +try { + Write-Log -Message "Starting uninstallation of $AppName" -Level Info + + # Check if running as administrator + $isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) + if (-not $isAdmin) { + Write-Log -Message "Script must be run as administrator" -Level Error + exit 1 + } + + # Check if application is installed + Write-Log -Message "Checking if $AppName is installed..." -Level Info + + # Uninstall using Product Code (MSI) + if ($ProductCode) { + Write-Log -Message "Uninstalling using Product Code: $ProductCode" -Level Info + $msiArgs = "/x `"$ProductCode`" /qn /norestart" + Write-Log -Message "Executing: msiexec.exe $msiArgs" -Level Info + $process = Start-Process -FilePath "msiexec.exe" -ArgumentList $msiArgs -Wait -PassThru + + if ($process.ExitCode -eq 0) { + Write-Log -Message "MSI uninstallation completed successfully" -Level Info + } else { + Write-Log -Message "MSI uninstallation failed with exit code: $($process.ExitCode)" -Level Error + exit $process.ExitCode + } + } + # Uninstall using UninstallString + elseif ($UninstallString) { + Write-Log -Message "Uninstalling using uninstall string: $UninstallString" -Level Info + $process = Start-Process -FilePath "cmd.exe" -ArgumentList "/c $UninstallString" -Wait -PassThru + + if ($process.ExitCode -eq 0) { + Write-Log -Message "Uninstallation completed successfully" -Level Info + } else { + Write-Log -Message "Uninstallation failed with exit code: $($process.ExitCode)" -Level Error + exit $process.ExitCode + } + } + # Try to find and uninstall automatically + else { + Write-Log -Message "Searching for installed application..." -Level Info + $installedApps = Get-InstalledApplication -AppName $AppName + + if ($installedApps.Count -eq 0) { + Write-Log -Message "$AppName is not installed" -Level Warning + exit 0 + } + + foreach ($app in $installedApps) { + Write-Log -Message "Found: $($app.DisplayName) - Version: $($app.DisplayVersion)" -Level Info + + if ($app.UninstallString) { + Write-Log -Message "Uninstalling using: $($app.UninstallString)" -Level Info + + # Handle different uninstall string formats + if ($app.UninstallString -like "msiexec*") { + # MSI uninstall + $uninstallArgs = $app.UninstallString -replace "msiexec.exe", "" -replace "/I", "/x" + $uninstallArgs += " /qn /norestart" + $process = Start-Process -FilePath "msiexec.exe" -ArgumentList $uninstallArgs -Wait -PassThru + } else { + # EXE uninstall + $process = Start-Process -FilePath "cmd.exe" -ArgumentList "/c `"$($app.UninstallString)`" /S /silent" -Wait -PassThru + } + + if ($process.ExitCode -eq 0 -or $process.ExitCode -eq 3010) { + Write-Log -Message "Uninstallation completed successfully" -Level Info + } else { + Write-Log -Message "Uninstallation failed with exit code: $($process.ExitCode)" -Level Error + } + } + } + } + + # Post-uninstallation cleanup + Write-Log -Message "Performing post-uninstallation cleanup..." -Level Info + + # Add any cleanup tasks here + # Examples: + # - Remove leftover directories + # - Clean up registry entries + # - Remove shortcuts + + Write-Log -Message "Uninstallation of $AppName completed successfully" -Level Info + exit 0 + +} catch { + Write-Log -Message "Uninstallation failed: $($_.Exception.Message)" -Level Error + Write-Log -Message "Stack trace: $($_.ScriptStackTrace)" -Level Error + exit 1 +} diff --git a/README.md b/README.md index f83cf98..43b21ff 100644 --- a/README.md +++ b/README.md @@ -1 +1,177 @@ -# kd7dgf_windows_scripts \ No newline at end of file +# KD7DGF Windows Scripts + +A collection of PowerShell scripts for deploying and managing applications through Microsoft Intune. + +## Overview + +This repository contains PowerShell scripts designed to facilitate application deployment via Microsoft Intune. The scripts follow best practices for Intune Win32 app deployment and include templates that can be customized for various applications. + +## Repository Structure + +``` +Intune/ +├── Templates/ # Reusable script templates +│ ├── Install-Application.ps1 # Installation template +│ ├── Uninstall-Application.ps1 # Uninstallation template +│ └── Detection-Application.ps1 # Detection template +└── Examples/ # Example implementations + ├── Install-7Zip.ps1 + ├── Detection-7Zip.ps1 + ├── Uninstall-7Zip.ps1 + ├── Install-GoogleChrome.ps1 + └── Detection-GoogleChrome.ps1 +``` + +## Templates + +### Install-Application.ps1 +A comprehensive template for installing applications via Intune. Features include: +- Support for MSI and EXE installers +- Detailed logging to `%ProgramData%\Intune\Logs` +- Administrator privilege checking +- Pre and post-installation tasks +- Error handling and exit codes + +**Usage:** +```powershell +.\Install-Application.ps1 -AppName "MyApp" -InstallerPath "C:\Temp\setup.msi" +``` + +### Uninstall-Application.ps1 +Template for uninstalling applications. Features include: +- Support for MSI Product Code uninstallation +- Automatic application discovery via registry +- UninstallString execution +- Post-uninstallation cleanup +- Comprehensive logging + +**Usage:** +```powershell +.\Uninstall-Application.ps1 -AppName "MyApp" -ProductCode "{GUID}" +``` + +### Detection-Application.ps1 +Template for detecting installed applications. Intune uses detection scripts to determine if an application is already installed. Features include: +- Multiple detection methods (file path, registry, installed apps) +- Version comparison support +- Proper exit codes for Intune + +**Usage:** +```powershell +.\Detection-Application.ps1 -AppName "MyApp" -Version "1.0.0" +``` + +## Example Scripts + +### 7-Zip Deployment +Complete set of scripts for deploying 7-Zip: +- `Install-7Zip.ps1` - Installs 7-Zip from MSI +- `Detection-7Zip.ps1` - Detects 7-Zip installation +- `Uninstall-7Zip.ps1` - Removes 7-Zip + +**Requirements:** +- Download 7-Zip MSI from [7-zip.org](https://www.7-zip.org/download.html) +- Place MSI in same directory as install script + +### Google Chrome Deployment +Scripts for deploying Google Chrome Enterprise: +- `Install-GoogleChrome.ps1` - Installs Chrome from MSI +- `Detection-GoogleChrome.ps1` - Detects Chrome installation + +**Requirements:** +- Download Chrome Enterprise MSI from [Google Chrome Enterprise](https://cloud.google.com/chrome-enterprise/browser/download/) +- Place MSI in same directory as install script + +## Using with Intune + +### Packaging Win32 Apps + +1. **Prepare your files:** + - Installation script (e.g., `Install-7Zip.ps1`) + - Installer file (MSI or EXE) + - Any additional files required + +2. **Download the Microsoft Win32 Content Prep Tool:** + ```powershell + # Download from: https://github.com/Microsoft/Microsoft-Win32-Content-Prep-Tool + ``` + +3. **Create the .intunewin package:** + ```powershell + .\IntuneWinAppUtil.exe -c "C:\Source" -s "Install-App.ps1" -o "C:\Output" + ``` + +4. **Upload to Intune:** + - Go to Microsoft Endpoint Manager admin center + - Apps > All apps > Add + - Select "Windows app (Win32)" + - Upload the .intunewin file + +5. **Configure the app:** + - **Install command:** `powershell.exe -ExecutionPolicy Bypass -File Install-App.ps1` + - **Uninstall command:** `powershell.exe -ExecutionPolicy Bypass -File Uninstall-App.ps1` + - **Detection rules:** Use custom script and upload your detection script + +### Best Practices + +1. **Logging:** + - All scripts log to `%ProgramData%\Intune\Logs` + - Review logs for troubleshooting + +2. **Testing:** + - Always test scripts locally before deploying via Intune + - Test on a clean system to verify detection logic + - Verify both install and uninstall work correctly + +3. **Exit Codes:** + - 0 = Success + - 1 = General failure + - 3010 = Success with restart required + - Other codes = Specific installer errors + +4. **Detection Scripts:** + - Must exit with code 0 + - Output to stdout = detected + - No output = not detected + - Error (exit code 1) = detection failed + +5. **Execution Policy:** + - Scripts should be run with `-ExecutionPolicy Bypass` + - Intune runs scripts in SYSTEM context + +## Customizing Templates + +To create a new deployment script: + +1. Copy the appropriate template from `Intune/Templates/` +2. Modify the installation/uninstallation logic for your application +3. Update detection logic to match your application's installation +4. Test thoroughly before deploying + +## Requirements + +- Windows 10/11 or Windows Server 2016+ +- PowerShell 5.1 or later +- Administrator privileges for installation/uninstallation +- Microsoft Intune subscription (for Intune deployment) + +## Contributing + +Feel free to submit pull requests with: +- New example scripts for common applications +- Improvements to existing templates +- Bug fixes or enhancements + +## License + +This project is provided as-is for use with Microsoft Intune deployments. + +## Author + +KD7DGF + +## Version History + +- **1.0** (2025-10-11) - Initial release + - Installation, Uninstallation, and Detection templates + - Example scripts for 7-Zip and Google Chrome \ No newline at end of file From 8361482a8d75d4fd08ebfd1da8e809d5c1c9ace1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 11 Oct 2025 17:12:23 +0000 Subject: [PATCH 3/3] Add system requirements checker and comprehensive Intune documentation Co-authored-by: AlwaysLearningTech <37163053+AlwaysLearningTech@users.noreply.github.com> --- Intune/README.md | 290 ++++++++++++++++++ Intune/Templates/Check-SystemRequirements.ps1 | 144 +++++++++ 2 files changed, 434 insertions(+) create mode 100644 Intune/README.md create mode 100644 Intune/Templates/Check-SystemRequirements.ps1 diff --git a/Intune/README.md b/Intune/README.md new file mode 100644 index 0000000..1e28336 --- /dev/null +++ b/Intune/README.md @@ -0,0 +1,290 @@ +# Intune Deployment Scripts + +This directory contains PowerShell scripts for deploying Win32 applications through Microsoft Intune. + +## Directory Structure + +### Templates/ +Production-ready script templates that can be customized for any application: + +- **Install-Application.ps1** - Universal installation template +- **Uninstall-Application.ps1** - Universal uninstallation template +- **Detection-Application.ps1** - Universal detection template +- **Check-SystemRequirements.ps1** - System requirements validation + +### Examples/ +Complete working examples for common applications: + +- **7-Zip** - Complete deployment package (install, detect, uninstall) +- **Google Chrome** - Browser deployment example (install, detect) + +## Quick Start + +### 1. Choose Your Approach + +**Option A: Use Templates (Recommended for custom apps)** +```powershell +# Copy template +Copy-Item Templates\Install-Application.ps1 MyApp\Install-MyApp.ps1 + +# Customize for your application +# Edit the installation logic section +``` + +**Option B: Use Examples (For supported apps)** +```powershell +# Use as-is or customize +# Download required installer +# Deploy via Intune +``` + +### 2. Create Intune Package + +```powershell +# Package structure +MyApp\ + ├── Install-MyApp.ps1 + ├── Detection-MyApp.ps1 + ├── Uninstall-MyApp.ps1 + └── setup.msi (or .exe) + +# Create .intunewin package +.\IntuneWinAppUtil.exe -c "C:\MyApp" -s "Install-MyApp.ps1" -o "C:\Output" +``` + +### 3. Configure in Intune + +1. **Upload .intunewin** to Intune portal +2. **Install command:** + ``` + powershell.exe -ExecutionPolicy Bypass -File Install-MyApp.ps1 + ``` +3. **Uninstall command:** + ``` + powershell.exe -ExecutionPolicy Bypass -File Uninstall-MyApp.ps1 + ``` +4. **Detection rule:** Custom script - upload Detection-MyApp.ps1 + +## Script Parameters + +### Install-Application.ps1 + +| Parameter | Required | Description | +|-----------|----------|-------------| +| AppName | Yes | Application name for logging | +| InstallerPath | No | Path to installer file | +| InstallPath | No | Custom installation directory | +| Arguments | No | Additional installer arguments | + +### Uninstall-Application.ps1 + +| Parameter | Required | Description | +|-----------|----------|-------------| +| AppName | Yes | Application name for logging | +| ProductCode | No | MSI product code GUID | +| UninstallString | No | Custom uninstall command | + +### Detection-Application.ps1 + +| Parameter | Required | Description | +|-----------|----------|-------------| +| AppName | Yes | Application name to search for | +| Version | No | Minimum version required | +| InstallPath | No | File path to check | +| RegistryPath | No | Registry key to check | +| RegistryValue | No | Registry value to check | + +### Check-SystemRequirements.ps1 + +| Parameter | Required | Description | +|-----------|----------|-------------| +| MinimumRAMGB | No | Minimum RAM in GB | +| MinimumDiskSpaceGB | No | Minimum free disk space in GB | +| MinimumOSVersion | No | Minimum Windows version | +| RequiredFeatures | No | Array of required Windows features | +| OutputDetails | No | Switch to show detailed output | + +## Detection Script Guidelines + +Detection scripts are critical for Intune to determine installation state: + +### Return Codes +- **Exit 0 with output** = Application detected (installed) +- **Exit 0 without output** = Application not detected (not installed) +- **Exit 1** = Error during detection + +### Example Detection Methods + +**Method 1: File Path** +```powershell +if (Test-Path "C:\Program Files\MyApp\app.exe") { + Write-Host "MyApp detected" + exit 0 +} +exit 0 +``` + +**Method 2: Registry** +```powershell +$regPath = "HKLM:\SOFTWARE\MyApp" +if (Test-Path $regPath) { + Write-Host "MyApp detected" + exit 0 +} +exit 0 +``` + +**Method 3: Version Check** +```powershell +$app = Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*" | + Where-Object { $_.DisplayName -like "*MyApp*" } + +if ($app -and $app.DisplayVersion -ge "1.0") { + Write-Host "MyApp version $($app.DisplayVersion) detected" + exit 0 +} +exit 0 +``` + +## Logging + +All scripts log to: `%ProgramData%\Intune\Logs\` + +Log files are named: `Install-AppName.log`, `Uninstall-AppName.log` + +### Log Levels +- **Info** - Normal operation (Green) +- **Warning** - Non-critical issues (Yellow) +- **Error** - Failures (Red) + +### Accessing Logs +```powershell +# View latest log +Get-Content "$env:ProgramData\Intune\Logs\Install-MyApp.log" -Tail 50 + +# View all logs +Get-ChildItem "$env:ProgramData\Intune\Logs" +``` + +## Common Installer Types + +### MSI Installers +```powershell +# Silent install +msiexec.exe /i "installer.msi" /qn /norestart + +# With logging +msiexec.exe /i "installer.msi" /qn /norestart /l*v "install.log" + +# Uninstall +msiexec.exe /x "{PRODUCT-CODE-GUID}" /qn /norestart +``` + +### EXE Installers +Common silent switches: +- `/S` or `/silent` - Most installers +- `/quiet` - Microsoft installers +- `/verysilent` - Inno Setup installers +- `-silent` - NSIS installers + +```powershell +# Silent install +Start-Process "installer.exe" -ArgumentList "/S" -Wait + +# Check exit code +$process = Start-Process "installer.exe" -ArgumentList "/S" -Wait -PassThru +if ($process.ExitCode -eq 0) { + Write-Host "Success" +} +``` + +## Testing Scripts + +### Local Testing +```powershell +# Test as SYSTEM (Intune context) +psexec -i -s powershell.exe + +# Run installation +.\Install-MyApp.ps1 -AppName "MyApp" -InstallerPath "setup.msi" + +# Test detection +.\Detection-MyApp.ps1 -AppName "MyApp" + +# Test uninstallation +.\Uninstall-MyApp.ps1 -AppName "MyApp" +``` + +### Validation Checklist +- [ ] Script runs without errors +- [ ] Installation completes successfully +- [ ] Detection script returns correct state +- [ ] Uninstallation removes the application +- [ ] Logs are created in expected location +- [ ] Exit codes are correct +- [ ] Works in SYSTEM context + +## Exit Codes Reference + +| Code | Meaning | +|------|---------| +| 0 | Success | +| 1 | General failure | +| 1602 | User cancelled installation | +| 1603 | Fatal error during installation | +| 1618 | Another installation in progress | +| 1641 | Success, restart initiated | +| 3010 | Success, restart required | + +## Troubleshooting + +### Common Issues + +**Issue: Script execution is blocked** +```powershell +# Solution: Use -ExecutionPolicy Bypass +powershell.exe -ExecutionPolicy Bypass -File script.ps1 +``` + +**Issue: Application not detected after installation** +- Check detection script logic +- Verify file paths are correct +- Ensure detection runs in SYSTEM context +- Review detection script output manually + +**Issue: Installation fails silently** +- Check installer logs +- Verify installer is correct architecture (x64/x86) +- Test installer manually with same parameters +- Check system requirements + +**Issue: Logs not created** +- Verify `%ProgramData%\Intune\Logs` directory exists +- Check script has write permissions +- Run script as administrator + +## Best Practices + +1. **Always test locally** before deploying to Intune +2. **Use SYSTEM context** for testing (matches Intune) +3. **Handle errors gracefully** with try-catch blocks +4. **Log everything** for troubleshooting +5. **Check prerequisites** before installation +6. **Use proper exit codes** for Intune to understand results +7. **Keep scripts simple** - avoid unnecessary complexity +8. **Document customizations** in script comments +9. **Version your scripts** for tracking changes +10. **Test uninstall** as thoroughly as install + +## Additional Resources + +- [Microsoft Intune Win32 App Management](https://docs.microsoft.com/en-us/mem/intune/apps/apps-win32-app-management) +- [Win32 Content Prep Tool](https://github.com/Microsoft/Microsoft-Win32-Content-Prep-Tool) +- [PowerShell Documentation](https://docs.microsoft.com/en-us/powershell/) + +## Support + +For issues or questions: +- Review logs in `%ProgramData%\Intune\Logs` +- Check Intune device diagnostics +- Consult Microsoft Endpoint Manager admin center diff --git a/Intune/Templates/Check-SystemRequirements.ps1 b/Intune/Templates/Check-SystemRequirements.ps1 new file mode 100644 index 0000000..8496bae --- /dev/null +++ b/Intune/Templates/Check-SystemRequirements.ps1 @@ -0,0 +1,144 @@ +<# +.SYNOPSIS + System Requirements Check for Intune Deployments + +.DESCRIPTION + Verifies that the system meets requirements before application installation. + Can be used as a requirement rule in Intune or as a pre-check in install scripts. + +.PARAMETER MinimumRAMGB + Minimum RAM required in GB + +.PARAMETER MinimumDiskSpaceGB + Minimum free disk space required in GB on system drive + +.PARAMETER MinimumOSVersion + Minimum Windows version (e.g., "10.0.19041" for Windows 10 20H2) + +.PARAMETER RequiredFeatures + Array of Windows features that must be enabled + +.EXAMPLE + .\Check-SystemRequirements.ps1 -MinimumRAMGB 4 -MinimumDiskSpaceGB 10 -MinimumOSVersion "10.0.19041" + +.NOTES + Author: KD7DGF + Version: 1.0 + Date: 2025-10-11 + + Exit codes: + 0 = Requirements met + 1 = Requirements not met +#> + +[CmdletBinding()] +param( + [Parameter(Mandatory=$false)] + [int]$MinimumRAMGB, + + [Parameter(Mandatory=$false)] + [int]$MinimumDiskSpaceGB, + + [Parameter(Mandatory=$false)] + [string]$MinimumOSVersion, + + [Parameter(Mandatory=$false)] + [string[]]$RequiredFeatures, + + [Parameter(Mandatory=$false)] + [switch]$OutputDetails +) + +# Set error action preference +$ErrorActionPreference = "Stop" + +function Write-Result { + param( + [string]$Check, + [bool]$Passed, + [string]$Details + ) + + $status = if ($Passed) { "PASS" } else { "FAIL" } + $color = if ($Passed) { "Green" } else { "Red" } + + if ($OutputDetails) { + Write-Host "[$status] $Check - $Details" -ForegroundColor $color + } + + return $Passed +} + +try { + $allChecksPassed = $true + + # Check RAM + if ($MinimumRAMGB) { + $totalRAM = [math]::Round((Get-CimInstance Win32_ComputerSystem).TotalPhysicalMemory / 1GB, 2) + $ramCheck = $totalRAM -ge $MinimumRAMGB + $allChecksPassed = $allChecksPassed -and (Write-Result -Check "RAM" -Passed $ramCheck -Details "$totalRAM GB (Required: $MinimumRAMGB GB)") + } + + # Check Disk Space + if ($MinimumDiskSpaceGB) { + $systemDrive = $env:SystemDrive + $disk = Get-CimInstance Win32_LogicalDisk | Where-Object { $_.DeviceID -eq $systemDrive } + $freeSpaceGB = [math]::Round($disk.FreeSpace / 1GB, 2) + $diskCheck = $freeSpaceGB -ge $MinimumDiskSpaceGB + $allChecksPassed = $allChecksPassed -and (Write-Result -Check "Disk Space" -Passed $diskCheck -Details "$freeSpaceGB GB free (Required: $MinimumDiskSpaceGB GB)") + } + + # Check OS Version + if ($MinimumOSVersion) { + $osVersion = [System.Environment]::OSVersion.Version + $currentVersion = "$($osVersion.Major).$($osVersion.Minor).$($osVersion.Build)" + + try { + $current = [Version]$currentVersion + $required = [Version]$MinimumOSVersion + $osCheck = $current -ge $required + } catch { + $osCheck = $currentVersion -ge $MinimumOSVersion + } + + $allChecksPassed = $allChecksPassed -and (Write-Result -Check "OS Version" -Passed $osCheck -Details "$currentVersion (Required: $MinimumOSVersion)") + } + + # Check Windows Features + if ($RequiredFeatures) { + foreach ($feature in $RequiredFeatures) { + $featureState = Get-WindowsOptionalFeature -Online -FeatureName $feature -ErrorAction SilentlyContinue + + if ($featureState) { + $featureCheck = $featureState.State -eq "Enabled" + $state = $featureState.State + } else { + $featureCheck = $false + $state = "Not Found" + } + + $allChecksPassed = $allChecksPassed -and (Write-Result -Check "Feature: $feature" -Passed $featureCheck -Details $state) + } + } + + # Check if system is 64-bit + $is64Bit = [Environment]::Is64BitOperatingSystem + $allChecksPassed = $allChecksPassed -and (Write-Result -Check "64-bit OS" -Passed $is64Bit -Details $(if ($is64Bit) { "Yes" } else { "No (32-bit)" })) + + # Final result + if ($allChecksPassed) { + if ($OutputDetails) { + Write-Host "`n✓ All system requirements met" -ForegroundColor Green + } + exit 0 + } else { + if ($OutputDetails) { + Write-Host "`n✗ System requirements not met" -ForegroundColor Red + } + exit 1 + } + +} catch { + Write-Error "Requirements check failed: $($_.Exception.Message)" + exit 1 +}