From 36aaec424cd214027deca924f164ba76b774e06a Mon Sep 17 00:00:00 2001 From: Ben Odom Date: Wed, 22 Oct 2025 14:01:19 -0700 Subject: [PATCH] Initial AIPC SDK 2.0 Commit --- .gitignore | 49 + LICENSE | 21 + Linux_Software_Installation/README.md | 455 ++++++ .../Utilities/compatibility_check.sh | 385 +++++ .../Utilities/compatibility_check_README.md | 75 + .../Utilities/verify_connectivity.sh | 131 ++ .../build-static-installer.sh | 1292 +++++++++++++++++ Linux_Software_Installation/setup-software.sh | 303 ++++ README.md | 239 ++- .../OVMS/README_OVMS.md | 134 ++ .../OVMS/ovms_setup.ps1 | 289 ++++ Windows_Software_Installation/README.md | 306 ++++ .../JSON/install/applications.json | 140 ++ .../Public/Append-ToJson.ps1 | 365 +++++ .../WingetGUI_Installer/Public/GUI.ps1 | 605 ++++++++ .../WingetGUI_Installer/Public/Install.ps1 | 314 ++++ .../WingetGUI_Installer/Public/Pre_Req.ps1 | 146 ++ .../Public/Run_Once_Eula.ps1 | 113 ++ .../WingetGUI_Installer/Public/Uninstall.ps1 | 390 +++++ .../Public/Write_ToLog.ps1 | 16 + .../WingetGUI_Installer/Setup_1.ps1 | 591 ++++++++ .../WingetGUI_Installer/Setup_2.ps1 | 867 +++++++++++ 22 files changed, 7224 insertions(+), 2 deletions(-) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Linux_Software_Installation/README.md create mode 100644 Linux_Software_Installation/Utilities/compatibility_check.sh create mode 100644 Linux_Software_Installation/Utilities/compatibility_check_README.md create mode 100644 Linux_Software_Installation/Utilities/verify_connectivity.sh create mode 100644 Linux_Software_Installation/build-static-installer.sh create mode 100644 Linux_Software_Installation/setup-software.sh create mode 100644 Windows_Software_Installation/OVMS/README_OVMS.md create mode 100644 Windows_Software_Installation/OVMS/ovms_setup.ps1 create mode 100644 Windows_Software_Installation/README.md create mode 100644 Windows_Software_Installation/WingetGUI_Installer/JSON/install/applications.json create mode 100644 Windows_Software_Installation/WingetGUI_Installer/Public/Append-ToJson.ps1 create mode 100644 Windows_Software_Installation/WingetGUI_Installer/Public/GUI.ps1 create mode 100644 Windows_Software_Installation/WingetGUI_Installer/Public/Install.ps1 create mode 100644 Windows_Software_Installation/WingetGUI_Installer/Public/Pre_Req.ps1 create mode 100644 Windows_Software_Installation/WingetGUI_Installer/Public/Run_Once_Eula.ps1 create mode 100644 Windows_Software_Installation/WingetGUI_Installer/Public/Uninstall.ps1 create mode 100644 Windows_Software_Installation/WingetGUI_Installer/Public/Write_ToLog.ps1 create mode 100644 Windows_Software_Installation/WingetGUI_Installer/Setup_1.ps1 create mode 100644 Windows_Software_Installation/WingetGUI_Installer/Setup_2.ps1 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7d94ba2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,49 @@ +# Generated files +setup-static-drivers.sh + +# IDE and editor directories +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS generated files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Temporary files +*.tmp +*.temp +/tmp/ +temp/ + +# Log files +*.log +logs/ +error.txt + +# Installer-specific generated files (winget_installer) +SetupScript/EnvSetup/logs/ +SetupScript/EnvSetup/json/uninstall/ +**/install_log.txt +**/error_log.txt +**/uninstall.txt +**/uninstall.json + +# Package files +*.deb +*.ddeb +*.rpm +*.tar.gz +*.zip + +# Backup files +*.bak +*.backup +*~ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9743b60 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Intel + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Linux_Software_Installation/README.md b/Linux_Software_Installation/README.md new file mode 100644 index 0000000..cfc6c3d --- /dev/null +++ b/Linux_Software_Installation/README.md @@ -0,0 +1,455 @@ +# Intel AI PC Linux Setup Guide + +Complete guide for setting up Intel AI PC development on Linux, including driver installation and AI software environment setup. + +--- + +## 🔧 Part 1: Driver Setup (Required First) + +> **⚠️ CRITICAL: Install Drivers Before AI Software** +> +> You **must** install Intel GPU and NPU drivers before installing any AI development software. The AI frameworks and tools require proper driver support to function correctly. + +### Overview + +This directory contains scripts to set up Intel GPU and NPU drivers on Ubuntu 24.04 for AI PC platforms. The setup builds an installation script that represents the latest versions of the drivers that work together. + +**Available Scripts:** +- **`build-static-installer.sh`**: ⭐ Static installer builder (no GitHub token required) +- **`setup-static-drivers.sh`**: Generated static driver installation script (no API dependencies) +- **`Utilities/verify_connectivity.sh`**: Diagnostic tools for troubleshooting GitHub API connectivity issues + +### Driver Installation Steps + +#### Step 1: Build and Run Static Installer ⭐ + +**No GitHub token required** + +```bash +# Navigate to driver setup directory +cd Linux_Driver_Setup + +# Step 1: Build static installer with compatibility checking +./build-static-installer.sh --build-static + +# Step 2: Run the generated static installer +sudo ./setup-static-drivers.sh +``` + +## Troubleshooting + + +#### GitHub API Rate Limiting +**Problem**: Installation fails with rate limit errors -- this sometimes happens if you are at a company behind a proxy and it appears that many users are sharing the same iP address. +**Solution**: Set GITHUB_TOKEN environment variable +```bash +export GITHUB_TOKEN=your_token_here +sudo -E ./setup-static-drivers.sh # -E preserves environment variables +``` + +#### Network Connectivity +**Problem**: Cannot reach GitHub +**Solution**: Check your internet connection and firewall settings +```bash +# Test basic connectivity +curl https://github.com + +# Run full diagnostic +./verify_connectivity.sh +``` + +#### Permission Issues +**Problem**: Script fails due to insufficient privileges +**Solution**: Run with sudo +```bash +sudo ./setup-static-drivers.sh +``` + +### Diagnostic Script Output + +The `verify_connectivity.sh` script performs these checks: + +1. **HTTPS Connectivity**: Tests connection to github.com +2. **GitHub API Access**: Verifies API accessibility and rate limits +3. **Repository Testing**: Checks latest versions for all required repositories: + - intel/intel-graphics-compiler + - intel/compute-runtime + - intel/linux-npu-driver + - oneapi-src/level-zero + +#### Successful Output Example + +```text +=== Simple Driver Version Test === + +1. Testing HTTPS connectivity... + ✓ Can reach github.com via HTTPS +2. Testing GitHub API... + Using GitHub authentication token + ✓ GitHub API is accessible + +3. Testing specific repositories... + +Testing intel/intel-graphics-compiler: + ✓ Found version: v2.12.5 + +Testing intel/compute-runtime: + ✓ Found version: 25.22.33944.8 + +Testing intel/linux-npu-driver: + ✓ Found version: v1.17.0 + +Testing oneapi-src/level-zero: + ✓ Found version: v1.22.4 + +Test completed! +``` + +#### Rate Limited Output Example + +```text +=== Simple Driver Version Test === + +1. Testing HTTPS connectivity... + ✓ Can reach github.com via HTTPS +2. Testing GitHub API... + ✗ GitHub API rate limit exceeded + + To fix this issue: + 1. Set your GitHub token: export GITHUB_TOKEN=your_token_here + 2. Get a token at: https://github.com/settings/tokens + 3. Re-run this script +``` + + +### Updating Static Installers + +To update to newer driver versions: + +```bash +# Regenerate with latest versions +./build-static-installer.sh --build-static + +# The static installer will be updated with new URLs +sudo ./setup-static-drivers.sh +``` + +### Environment Variables + +- **`GITHUB_TOKEN`**: Personal access token for GitHub API (recommended) +- **`OS_ID`**: Target OS identifier (default: "ubuntu") +- **`OS_VERSION`**: Target OS version (default: "24.04") + +### Manual Package Selection + +The script automatically downloads the latest versions, but you can check what versions would be installed: + +```bash +./Utilities/verify_connectivity.sh +``` + +--- + +## 🚀 Part 2: Software Setup (After Driver Installation) + +> **⚠️ IMPORTANT: Driver Setup Required First** +> **⚠️ IMPORTANT: After installing drivers reboot the system before continuing to part 2.** +> +> Before running this software setup, ensure you have completed Part 1 (Driver Setup) above. The AI software components require proper Intel GPU and NPU drivers to function correctly. + +### Overview + +The `setup-software.sh` script (located in `../Linux_Software_Installation/`) is a comprehensive automation tool that sets up a complete AI development environment optimized for Intel AI PCs. It installs and configures essential AI/ML frameworks, development tools, notebooks, and sample applications. + +### What This Script Installs + +#### Core Development Tools + +- **UV Package Manager**: Fast Python package manager for efficient dependency management +- **Python Virtual Environments**: Proper isolation for AI projects +- **Google Chrome**: Browser for web-based AI applications and Jupyter notebooks +- **Visual Studio Code**: Popular IDE with AI development extensions + +#### AI/ML Frameworks and Toolkits + +- **OpenVINO Toolkit**: Intel's AI inference optimization framework +- **OpenVINO GenAI**: Generative AI toolkit with Intel optimizations +- **Ollama**: Local LLM runtime with Intel GPU acceleration + +#### Notebooks and Workshop Materials + +- **OpenVINO Notebooks**: Comprehensive collection of AI inference examples and tutorials +- **MSBuild 2025 Workshop**: Latest Intel AI PC development workshop materials +- **Additional Workshop Repositories**: Extra learning materials and sample projects + +#### Target Installation Directory + +All AI development materials are installed under `~/intel/` for organized project management. + +### Software Installation Steps + +#### Prerequisites + +- **Operating System**: Ubuntu 24.04 LTS (recommended) +- **Hardware**: Intel AI PC with compatible GPU and NPU +- **Drivers**: Intel GPU/NPU drivers installed (Part 1 above) +- **Memory**: At least 16GB RAM (32GB+ recommended for large models) +- **Storage**: At least 10GB free space for all components + +#### Installation Commands + +```bash +# Navigate to software setup directory +cd ../Linux_Software_Installation + +# Make the script executable +chmod +x setup-software.sh + +# Run the setup (DO NOT use sudo) +./setup-software.sh +``` + +**Important Notes:** +- **Never run with sudo**: The script explicitly prevents running as root for security +- **Interactive Installation**: Some components may require user input during installation +- **Time Requirements**: Full installation may take 30-60 minutes depending on internet speed +- **Resumability**: Script checks for existing installations and can be re-run safely + +### Installation Process + +#### Phase 1: System Preparation + +1. Verifies user permissions (prevents sudo execution) +2. Checks and installs system dependencies +3. Creates the `~/intel` working directory +4. Sets up error handling and logging + +#### Phase 2: Python Environment Setup + +1. Installs UV package manager for fast Python package management +2. Verifies Python 3 and pip installation +3. Sets up virtual environment capabilities + +#### Phase 3: AI Framework Installation + +1. **OpenVINO Notebooks**: Clones and sets up the comprehensive notebook collection +2. **MSBuild 2025 Workshop**: Installs latest Intel AI PC workshop materials +3. **OpenVINO GenAI**: Sets up generative AI toolkit with Intel optimizations +4. **Ollama**: Installs local LLM runtime with Intel GPU acceleration + +#### Phase 4: Development Tools + +1. **Google Chrome**: Installs browser for web-based development +2. **VS Code**: Installs popular IDE for AI development +3. **Additional Repositories**: Clones supplementary workshop materials + +### What Gets Installed Where + +```text +~/intel/ +├── openvino_notebooks/ # Main OpenVINO tutorial notebooks +├── MSBuild2025_NeuralChat/ # MSBuild 2025 workshop materials +├── openvino.genai/ # OpenVINO GenAI toolkit +├── WorkShops_BootCamp/ # Additional workshop materials +├── llm-on-ray/ # LLM on Ray examples +└── various Python virtual environments +``` + +**System-wide Installations:** +- **Ollama**: Installed system-wide via official installer +- **Google Chrome**: Installed via .deb package +- **VS Code**: Installed via official repository +- **UV**: Installed system-wide Python package manager + +### Post-Installation + +#### Verification Steps + +After installation completes, verify your setup: + +```bash +# Check Ollama installation +ollama --version + +# Check UV installation +uv --version + +# Check Chrome installation +google-chrome --version + +# Check VS Code installation +code --version + +# Verify Python environments +ls ~/intel/*/venv/ +``` + +#### Getting Started + +1. **Navigate to notebooks**: `cd ~/intel/openvino_notebooks` +2. **Activate environment**: `source venv/bin/activate` +3. **Start Jupyter**: `jupyter lab` +4. **Browse examples**: Explore the notebooks directory for AI examples + +#### Testing Ollama + +```bash +# Test Ollama with a simple model +ollama pull llama2:7b +ollama run llama2:7b "Hello, how are you?" +``` + +--- + +## 🛠️ Comprehensive Troubleshooting + +### Driver Issues + +#### GitHub API Rate Limiting +**Problem**: Installation fails with rate limit errors -- this sometimes happens if you are at a company behind a proxy and it appears that many users are sharing the same IP address. + +**Solution**: Set GITHUB_TOKEN environment variable +```bash +export GITHUB_TOKEN=your_token_here +sudo -E ./setup-static-drivers.sh # -E preserves environment variables +``` + +#### Network Connectivity +**Problem**: Cannot reach GitHub + +**Solution**: Check your internet connection and firewall settings +```bash +# Test basic connectivity +curl https://github.com + +# Run full diagnostic (from Linux_Driver_Setup directory) +./Utilities/verify_connectivity.sh +``` + +#### Permission Issues +**Problem**: Script fails due to insufficient privileges + +**Solution**: Run with sudo (drivers only) +```bash +sudo ./setup-static-drivers.sh +``` + +### Software Installation Issues + +#### Permission Errors + +- **Problem**: "Permission denied" errors during software installation +- **Solution**: Ensure you're not running with sudo and have write access to home directory + +#### Network Timeouts + +- **Problem**: Downloads fail due to network issues +- **Solution**: Check internet connection and re-run the script (it will skip completed installations) + +#### Python Environment Issues + +- **Problem**: Virtual environment creation fails +- **Solution**: Ensure python3-venv is installed: `sudo apt install python3-venv` + +#### Disk Space Issues + +- **Problem**: Installation fails due to insufficient space +- **Solution**: Free up at least 10GB of space and re-run + +#### GPU/NPU Recognition Issues + +- **Problem**: AI acceleration not working +- **Solution**: Verify drivers are properly installed using the diagnostic script + +### Log Files + +Installation logs are written to the terminal. For debugging: + +1. Re-run the script with verbose output: `bash -x setup-software.sh` +2. Check individual component logs in their respective directories + +--- + +## 📚 Advanced Configuration + +### Updating Components + +#### Driver Updates + +To update to newer driver versions: + +```bash +cd Linux_Driver_Setup + +# Regenerate with latest versions +./build-static-installer.sh --build-static + +# The static installer will be updated with new URLs +sudo ./setup-static-drivers.sh +``` + +#### Software Updates + +- **Ollama models**: `ollama pull ` +- **OpenVINO notebooks**: `cd ~/intel/openvino_notebooks && git pull` +- **VS Code**: Updates automatically or via system package manager +- **Chrome**: Updates automatically + +### Environment Variables + +#### Driver Setup Variables + +- **`GITHUB_TOKEN`**: Personal access token for GitHub API (recommended) +- **`OS_ID`**: Target OS identifier (default: "ubuntu") +- **`OS_VERSION`**: Target OS version (default: "24.04") + +#### Software Setup Variables + +- `HOME`: User home directory (used for ~/intel path) +- `PATH`: Updated with new tool locations + +### Customizing Installation + +The software script can be modified to skip certain components by commenting out function calls in the main execution section. + +### Removing Components + +To clean up the software installation: + +```bash +# Remove all AI development materials +rm -rf ~/intel/ + +# Uninstall system packages (optional) +sudo apt remove google-chrome-stable code ollama +``` + +--- + +## 📞 Support and Resources + +- **Intel AI PC Documentation**: [Intel Developer Zone](https://www.intel.com/content/www/us/en/developer/topic-technology/artificial-intelligence/overview.html) +- **OpenVINO Documentation**: [OpenVINO Toolkit](https://docs.openvino.ai/) +- **Issues**: Report problems via the project repository + +## 📄 Security Considerations + +- Driver scripts run with sudo for necessary system-level installations +- Software script prevents execution as root to avoid system-wide permission issues +- Downloads from official sources only (GitHub, official package repositories) +- Creates isolated Python environments to prevent dependency conflicts +- No modification of system-critical directories or configurations + +## Contributing + +When contributing to this project: + +1. Test changes with the diagnostic script first +2. Ensure compatibility with Ubuntu 24.04 +3. Update documentation for any new features +4. Follow the existing error handling patterns + +--- + +*This guide is part of the Intel AI PC development toolkit. Follow the steps in order: Drivers First (Part 1), then Software Setup (Part 2).* + diff --git a/Linux_Software_Installation/Utilities/compatibility_check.sh b/Linux_Software_Installation/Utilities/compatibility_check.sh new file mode 100644 index 0000000..5ac2d92 --- /dev/null +++ b/Linux_Software_Installation/Utilities/compatibility_check.sh @@ -0,0 +1,385 @@ +#!/bin/bash + +# Intel Driver Version Compatibility Checker +# This script checks for version compatibility between Intel Graphics Compiler (IGC) +# and Intel Compute Runtime packages to prevent dependency conflicts + +set -e + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +echo_info() { + echo -e "${GREEN}[INFO]${NC} $1" +} + +echo_warn() { + echo -e "${YELLOW}[WARN]${NC} $1" +} + +echo_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +echo_debug() { + echo -e "${BLUE}[DEBUG]${NC} $1" +} + +# Check GitHub token status +if [ -n "$GITHUB_TOKEN" ]; then + echo_info "GitHub token configured (${#GITHUB_TOKEN} characters)" + AUTH_HEADER="Authorization: token $GITHUB_TOKEN" +else + echo_warn "No GitHub token found - may hit rate limits" + echo_warn "Set GITHUB_TOKEN for better reliability" + AUTH_HEADER="" +fi + +# Function to get latest release tag +get_latest_release_tag() { + local repo="$1" + echo_debug "Getting latest release for $repo..." + + local response + if [ -n "$GITHUB_TOKEN" ]; then + response=$(curl -s -H "$AUTH_HEADER" "https://api.github.com/repos/$repo/releases/latest" 2>/dev/null) + else + response=$(curl -s "https://api.github.com/repos/$repo/releases/latest" 2>/dev/null) + fi + + # Check if curl failed or returned empty response + if [ -z "$response" ]; then + echo_error "Failed to connect to GitHub API for $repo" + return 1 + fi + + # Check if response is valid JSON and contains tag_name + if ! echo "$response" | jq -e '.tag_name' >/dev/null 2>&1; then + echo_error "Invalid response from GitHub API for $repo" + return 1 + fi + + local tag=$(echo "$response" | jq -r '.tag_name') + if [ "$tag" = "null" ] || [ -z "$tag" ]; then + echo_error "Could not extract tag_name from response for $repo" + return 1 + fi + + echo "$tag" + return 0 +} + +# Function to find compatible IGC version for compute runtime +find_compatible_igc_version() { + local compute_runtime_tag="$1" + echo_info "Finding compatible IGC version for compute runtime $compute_runtime_tag..." + + # Get the compute runtime release assets + local response + if [ -n "$GITHUB_TOKEN" ]; then + response=$(curl -s -H "$AUTH_HEADER" "https://api.github.com/repos/intel/compute-runtime/releases/tags/$compute_runtime_tag") + else + response=$(curl -s "https://api.github.com/repos/intel/compute-runtime/releases/tags/$compute_runtime_tag") + fi + + # Look for intel-opencl-icd package + local opencl_icd_url=$(echo "$response" | jq -r '.assets[] | select(.name | contains("intel-opencl-icd_")) | .browser_download_url' | head -1) + + if [ -n "$opencl_icd_url" ] && [ "$opencl_icd_url" != "null" ]; then + echo_debug "Downloading intel-opencl-icd package to check dependencies..." + + # Download the package temporarily + local temp_dir=$(mktemp -d) + cd "$temp_dir" + + if wget -q "$opencl_icd_url" -O opencl-icd.deb 2>/dev/null; then + # Extract control information + local deps_info=$(dpkg-deb --info opencl-icd.deb 2>/dev/null | grep -A 20 "Depends:" || echo "No dependencies found") + + # Look for IGC dependency + local igc_version=$(echo "$deps_info" | grep -o "intel-igc-opencl-2 (= [^)]*)" | sed 's/intel-igc-opencl-2 (= \([^)]*\))/\1/' | head -1) + + cd - > /dev/null + rm -rf "$temp_dir" + + if [ -n "$igc_version" ]; then + echo_info "Found required IGC version: $igc_version" + echo "$igc_version" + return 0 + fi + fi + + cd - > /dev/null + rm -rf "$temp_dir" + fi + + echo_error "Could not determine compatible IGC version" + return 1 +} + +# Function to find IGC release tag for a specific version +find_igc_tag_for_version() { + local target_version="$1" + echo_debug "Searching for IGC tag matching version $target_version..." + + # Get IGC releases to find matching tag + local response + if [ -n "$GITHUB_TOKEN" ]; then + response=$(curl -s -H "$AUTH_HEADER" "https://api.github.com/repos/intel/intel-graphics-compiler/releases?per_page=30") + else + response=$(curl -s "https://api.github.com/repos/intel/intel-graphics-compiler/releases?per_page=30") + fi + + # Look through releases for matching version + local matching_tag=$(echo "$response" | jq -r --arg version "$target_version" '.[] | select(.assets[].name | contains($version)) | .tag_name' | head -1) + + if [ -n "$matching_tag" ] && [ "$matching_tag" != "null" ]; then + echo_info "Found matching IGC tag: $matching_tag" + echo "$matching_tag" + return 0 + fi + + echo_warn "Could not find IGC tag for version $target_version" + + # Try alternative approach - look for tags that might contain the version + local alternative_tag=$(echo "$response" | jq -r '.[] | .tag_name' | grep -E "v?${target_version}" | head -1) + + if [ -n "$alternative_tag" ]; then + echo_info "Found alternative IGC tag: $alternative_tag" + echo "$alternative_tag" + return 0 + fi + + return 1 +} + +# Function to check version compatibility +check_version_compatibility() { + local igc_tag="$1" + local compute_runtime_tag="$2" + + echo_info "Checking compatibility between IGC $igc_tag and Compute Runtime $compute_runtime_tag..." + + # Create temp directory + local temp_dir=$(mktemp -d) + cd "$temp_dir" + + # Download a sample IGC package to check version + local igc_response + if [ -n "$GITHUB_TOKEN" ]; then + igc_response=$(curl -s -H "$AUTH_HEADER" "https://api.github.com/repos/intel/intel-graphics-compiler/releases/tags/$igc_tag") + else + igc_response=$(curl -s "https://api.github.com/repos/intel/intel-graphics-compiler/releases/tags/$igc_tag") + fi + + local igc_package_url=$(echo "$igc_response" | jq -r '.assets[] | select(.name | contains("intel-igc-opencl-2_")) | .browser_download_url' | head -1) + + # Download a sample Compute Runtime package + local cr_response + if [ -n "$GITHUB_TOKEN" ]; then + cr_response=$(curl -s -H "$AUTH_HEADER" "https://api.github.com/repos/intel/compute-runtime/releases/tags/$compute_runtime_tag") + else + cr_response=$(curl -s "https://api.github.com/repos/intel/compute-runtime/releases/tags/$compute_runtime_tag") + fi + + local cr_package_url=$(echo "$cr_response" | jq -r '.assets[] | select(.name | contains("intel-opencl-icd_")) | .browser_download_url' | head -1) + + if [ -n "$igc_package_url" ] && [ "$igc_package_url" != "null" ] && [ -n "$cr_package_url" ] && [ "$cr_package_url" != "null" ]; then + echo_debug "Downloading packages to check compatibility..." + + if wget -q "$igc_package_url" -O igc.deb 2>/dev/null && wget -q "$cr_package_url" -O cr.deb 2>/dev/null; then + # Extract IGC version from package + local igc_version=$(dpkg-deb --field igc.deb Version 2>/dev/null | cut -d'+' -f1) + + # Extract required IGC version from compute runtime dependencies + local required_igc=$(dpkg-deb --field cr.deb Depends 2>/dev/null | grep -o "intel-igc-opencl-2 (= [^)]*)" | sed 's/intel-igc-opencl-2 (= \([^)]*\))/\1/' | head -1) + + cd - > /dev/null + rm -rf "$temp_dir" + + if [ -n "$igc_version" ] && [ -n "$required_igc" ]; then + echo_info "IGC package version: $igc_version" + echo_info "Required IGC version: $required_igc" + + if [ "$igc_version" = "$required_igc" ]; then + echo_info "✅ Versions are compatible!" + return 0 + else + echo_error "❌ Version mismatch detected!" + echo_error " IGC provides: $igc_version" + echo_error " Runtime needs: $required_igc" + return 1 + fi + fi + fi + fi + + cd - > /dev/null + rm -rf "$temp_dir" + echo_warn "Could not determine compatibility" + return 1 +} + +# Function to collect compatible versions +collect_compatible_versions() { + echo_info "=== Collecting Compatible Driver Versions ===" + echo + + # First, get the latest compute runtime version + echo_info "Getting latest compute runtime version..." + local compute_runtime_tag=$(get_latest_release_tag "intel/compute-runtime") + if [ $? -ne 0 ]; then + echo_error "Failed to get compute runtime version" + return 1 + fi + echo_info "Latest compute runtime: $compute_runtime_tag" + + # Find compatible IGC version + local compatible_igc_version=$(find_compatible_igc_version "$compute_runtime_tag") + if [ $? -ne 0 ]; then + echo_warn "Could not determine compatible IGC version, using latest..." + IGC_TAG=$(get_latest_release_tag "intel/intel-graphics-compiler") + else + IGC_TAG=$(find_igc_tag_for_version "$compatible_igc_version") + if [ $? -ne 0 ]; then + echo_warn "Could not find IGC tag for version $compatible_igc_version, using latest..." + IGC_TAG=$(get_latest_release_tag "intel/intel-graphics-compiler") + fi + fi + + # Get other component versions + COMPUTE_RUNTIME_TAG="$compute_runtime_tag" + NPU_DRIVER_TAG=$(get_latest_release_tag "intel/linux-npu-driver") + LEVEL_ZERO_TAG=$(get_latest_release_tag "oneapi-src/level-zero") + + echo + echo_info "=== Selected Versions ===" + echo_info "IGC: $IGC_TAG" + echo_info "Compute Runtime: $COMPUTE_RUNTIME_TAG" + echo_info "NPU Driver: $NPU_DRIVER_TAG" + echo_info "Level Zero: $LEVEL_ZERO_TAG" + echo + + # Verify compatibility + echo_info "=== Verifying Compatibility ===" + if check_version_compatibility "$IGC_TAG" "$COMPUTE_RUNTIME_TAG"; then + echo_info "✅ All versions are compatible!" + return 0 + else + echo_error "❌ Version compatibility issues detected!" + return 1 + fi +} + +# Function to show usage +show_usage() { + cat << EOF +Usage: $0 [options] + +Options: + --check Check compatibility of current latest versions + --igc-tag Check specific IGC tag compatibility + --runtime-tag Check specific Compute Runtime tag compatibility + --help Show this help message + +Examples: + $0 --check # Check latest versions + $0 --igc-tag v2.14.1 --runtime-tag 25.22.33944.8 # Check specific versions + +Environment Variables: + GITHUB_TOKEN GitHub personal access token (recommended) +EOF +} + +# Main execution +main() { + local check_latest=false + local igc_tag="" + local runtime_tag="" + + # Parse command line arguments + while [[ $# -gt 0 ]]; do + case $1 in + --check) + check_latest=true + shift + ;; + --igc-tag) + igc_tag="$2" + shift 2 + ;; + --runtime-tag) + runtime_tag="$2" + shift 2 + ;; + --help) + show_usage + exit 0 + ;; + *) + echo_error "Unknown option: $1" + show_usage + exit 1 + ;; + esac + done + + # Check for required tools + if ! command -v jq &> /dev/null; then + echo_error "jq is required but not installed. Install with: sudo apt install jq" + exit 1 + fi + + if ! command -v curl &> /dev/null; then + echo_error "curl is required but not installed. Install with: sudo apt install curl" + exit 1 + fi + + echo_info "Intel Driver Version Compatibility Checker" + echo_info "==========================================" + echo + + if [ "$check_latest" = true ]; then + # Check compatibility of latest versions + if collect_compatible_versions; then + echo + echo_info "✅ Compatibility check passed!" + echo_info "These versions can be used together safely." + exit 0 + else + echo + echo_error "❌ Compatibility issues found!" + echo_error "Using these versions together may cause dependency conflicts." + exit 1 + fi + elif [ -n "$igc_tag" ] && [ -n "$runtime_tag" ]; then + # Check specific version compatibility + echo_info "Checking specific versions:" + echo_info "IGC: $igc_tag" + echo_info "Compute Runtime: $runtime_tag" + echo + + if check_version_compatibility "$igc_tag" "$runtime_tag"; then + echo + echo_info "✅ These versions are compatible!" + exit 0 + else + echo + echo_error "❌ These versions are NOT compatible!" + echo_error "This combination will cause dependency conflicts." + exit 1 + fi + else + echo_error "No action specified. Use --check or provide specific versions." + echo + show_usage + exit 1 + fi +} + +# Run main function with all arguments +main "$@" diff --git a/Linux_Software_Installation/Utilities/compatibility_check_README.md b/Linux_Software_Installation/Utilities/compatibility_check_README.md new file mode 100644 index 0000000..c104fcf --- /dev/null +++ b/Linux_Software_Installation/Utilities/compatibility_check_README.md @@ -0,0 +1,75 @@ +# Intel Driver Compatibility Checker (Optional Standalone Tool) + +> **Note**: Compatibility checking is now **integrated into the main script**. Most users should use: +> ```bash +> ./build-static-installer.sh --build-static +> ``` +> This standalone tool is **optional** and primarily useful for development, debugging, or testing specific version combinations. + +This script helps identify and resolve version compatibility issues between Intel Graphics Compiler (IGC) and Intel Compute Runtime packages. + +## Problem + +When using the latest Intel drivers, you may encounter dependency conflicts like: +``` +dpkg: dependency problems prevent configuration of intel-opencl-icd: + intel-opencl-icd depends on intel-igc-opencl-2 (= 2.12.5); however: + Version of intel-igc-opencl-2 on system is 2.14.1 +``` + +This happens because the Intel Graphics Compiler and Compute Runtime are released independently, and the latest versions may not always be compatible. + +## Solution + +The `compatibility_check.sh` script: +1. 📡 Downloads package metadata from GitHub releases +2. 🔍 Analyzes dependency requirements in .deb packages +3. ✅ Identifies compatible version combinations +4. 🛡️ Prevents installation of incompatible driver sets + +## Usage + +### Check Latest Versions +```bash +./compatibility_check.sh --check +``` + +### Check Specific Versions (Debugging) +```bash +./compatibility_check.sh --igc-tag v2.14.1 --runtime-tag 25.22.33944.8 +``` + +### Example Output +``` +[INFO] IGC package version: 2.14.1 +[INFO] Required IGC version: 2.12.5 +[ERROR] ❌ Version mismatch detected! +[ERROR] IGC provides: 2.14.1 +[ERROR] Runtime needs: 2.12.5 +``` + +## Environment Variables + +- `GITHUB_TOKEN`: Personal access token for higher API rate limits (recommended) + +## Integration Status + +✅ **Compatibility checking is now integrated** into `verify_latest_driver_names.sh --build-static` + +This standalone script is **optional** and mainly useful for: +- 🔧 **Development/debugging**: Testing specific version combinations +- 📊 **Manual verification**: Quick compatibility checks without generating static script +- 🛠️ **Troubleshooting**: Advanced users who want detailed compatibility analysis + +## Requirements + +- `jq` - JSON processor +- `curl` - HTTP client +- `dpkg-deb` - Debian package tools +- Internet connectivity to GitHub + +## Install Requirements + +```bash +sudo apt install jq curl +``` diff --git a/Linux_Software_Installation/Utilities/verify_connectivity.sh b/Linux_Software_Installation/Utilities/verify_connectivity.sh new file mode 100644 index 0000000..f80be74 --- /dev/null +++ b/Linux_Software_Installation/Utilities/verify_connectivity.sh @@ -0,0 +1,131 @@ +#!/bin/bash + +# Simple test script to show what driver versions would be downloaded +# This version has more robust error handling and debugging + +echo "=== Simple Driver Version Test ===" +echo +echo "Note: This script uses the GitHub API which has rate limits." + +# Check GitHub token status +if [ -n "$GITHUB_TOKEN" ]; then + echo "✓ GitHub token is configured (${#GITHUB_TOKEN} characters)" + echo " This will allow higher rate limits and better reliability." +else + echo "⚠ No GitHub token found in environment" + echo " Recommendation: Set GITHUB_TOKEN for better reliability:" + echo " 1. Get a token at: https://github.com/settings/tokens" + echo " 2. export GITHUB_TOKEN=your_token_here" + echo " 3. Re-run this script" +fi +echo + +# Test HTTPS connectivity +echo "1. Testing HTTPS connectivity..." +if curl -s --connect-timeout 5 --max-time 10 https://github.com > /dev/null; then + echo " ✓ Can reach github.com via HTTPS" +else + echo " ✗ Cannot reach github.com via HTTPS" + exit 1 +fi + +# Test GitHub API basic endpoint +echo "2. Testing GitHub API..." +if [ -n "$GITHUB_TOKEN" ]; then + echo " ✓ GitHub token is set (length: ${#GITHUB_TOKEN} characters)" + echo " Using authenticated requests..." + API_RESPONSE=$(curl -s --connect-timeout 5 --max-time 10 -H "Authorization: token $GITHUB_TOKEN" https://api.github.com) +else + echo " ⚠ No GitHub token set - using unauthenticated requests" + echo " Note: This may hit rate limits quickly. Set GITHUB_TOKEN for better reliability." + API_RESPONSE=$(curl -s --connect-timeout 5 --max-time 10 https://api.github.com) +fi + +if [ $? -eq 0 ] && echo "$API_RESPONSE" | grep -q "current_user_url"; then + echo " ✓ GitHub API is accessible" +elif echo "$API_RESPONSE" | grep -q "rate limit exceeded"; then + echo " ✗ GitHub API rate limit exceeded" + echo + echo " To fix this issue:" + echo " 1. Set your GitHub token: export GITHUB_TOKEN=your_token_here" + echo " 2. Get a token at: https://github.com/settings/tokens" + echo " 3. Re-run this script" + echo + exit 1 +else + echo " ✗ GitHub API is not accessible" + echo " Response: $API_RESPONSE" + exit 1 +fi + +# Simple function to get version with verbose output +get_version_simple() { + local repo="$1" + echo " Trying to fetch version for $repo..." + + local url="https://api.github.com/repos/$repo/releases/latest" + echo " URL: $url" + + local response + if [ -n "$GITHUB_TOKEN" ]; then + echo " Using authenticated request..." + response=$(curl -s --connect-timeout 10 --max-time 30 -H "Authorization: token $GITHUB_TOKEN" "$url") + else + echo " Using unauthenticated request..." + response=$(curl -s --connect-timeout 10 --max-time 30 "$url") + fi + local exit_code=$? + + if [ $exit_code -ne 0 ]; then + echo " curl failed with exit code: $exit_code" + return 1 + fi + + if [ -z "$response" ]; then + echo " Empty response" + return 1 + fi + + # Check if it's an error response + if echo "$response" | grep -q '"message"'; then + echo " API Error:" + echo "$response" | grep '"message"' | head -1 + return 1 + fi + + local version=$(echo "$response" | grep '"tag_name":' | head -1 | sed -E 's/.*"tag_name": *"([^"]+)".*/\1/') + + if [ -z "$version" ]; then + echo " Could not parse version from response" + echo " First 200 chars of response: $(echo "$response" | head -c 200)" + return 1 + fi + + echo " ✓ Found version: $version" + echo "$version" +} + +echo +echo "3. Testing specific repositories..." + +# Test each repository +repos=( + "intel/intel-graphics-compiler" + "intel/compute-runtime" + "intel/linux-npu-driver" + "oneapi-src/level-zero" +) + +for repo in "${repos[@]}"; do + echo + echo "Testing $repo:" + version=$(get_version_simple "$repo") + if [ $? -eq 0 ]; then + echo " Result: $version" + else + echo " Result: FAILED" + fi +done + +echo +echo "Test completed!" diff --git a/Linux_Software_Installation/build-static-installer.sh b/Linux_Software_Installation/build-static-installer.sh new file mode 100644 index 0000000..01c16ae --- /dev/null +++ b/Linux_Software_Installation/build-static-installer.sh @@ -0,0 +1,1292 @@ +#!/bin/bash + +# Intel Driver Static Installer Builder +# This script generates a static driver installation script with compatibility-checked versions +# Use --build-static flag to generate setup-static-drivers.sh with exact filenames and URLs + +set -e + +# Parse command line arguments +BUILD_STATIC=false +if [ "$1" = "--build-static" ]; then + BUILD_STATIC=true + echo "=== Building Static Driver Setup Script ===" + echo "Will generate setup-static-drivers.sh with exact filenames" + echo +fi + +echo "=== Intel Driver Static Installer Builder ===" +echo "This script builds a static driver installation script with compatibility checking" +echo "No files will be downloaded or installed by this builder script" +echo + +# Check GitHub token status +if [ -n "$GITHUB_TOKEN" ]; then + echo "✓ GitHub token is configured (${#GITHUB_TOKEN} characters)" + echo " Using authenticated requests for higher rate limits" + AUTH_HEADER="Authorization: token $GITHUB_TOKEN" +else + echo "⚠ No GitHub token found in environment" + echo " Using unauthenticated requests (may hit rate limits quickly)" + echo " Recommendation: Set GITHUB_TOKEN for better reliability" + AUTH_HEADER="" +fi +echo + +# Check if jq is available +if ! command -v jq &> /dev/null; then + echo "Error: jq is required but not installed. Install with: sudo apt install jq" + exit 1 +fi + +# Function to safely get latest release tag +get_latest_release_tag() { + local repo="$1" + echo "Checking latest release for $repo..." >&2 + + local response + if [ -n "$GITHUB_TOKEN" ]; then + response=$(curl -s -H "$AUTH_HEADER" "https://api.github.com/repos/$repo/releases/latest" 2>/dev/null) + else + response=$(curl -s "https://api.github.com/repos/$repo/releases/latest" 2>/dev/null) + fi + + # Check if curl failed or returned empty response + if [ -z "$response" ]; then + echo "ERROR: Failed to connect to GitHub API for $repo" >&2 + return 1 + fi + + # Check if response is valid JSON + if ! echo "$response" | jq . >/dev/null 2>&1; then + echo "ERROR: Invalid JSON response from GitHub API for $repo" >&2 + echo "Response preview: $(echo "$response" | head -1)" >&2 + return 1 + fi + + # Check if we got rate limited + if echo "$response" | jq -r '.message' 2>/dev/null | grep -q "rate limit"; then + echo "ERROR: GitHub API rate limit exceeded" >&2 + echo "Solution: Set GITHUB_TOKEN environment variable with a personal access token" >&2 + echo "Visit: https://github.com/settings/tokens" >&2 + return 1 + fi + + local tag=$(echo "$response" | jq -r '.tag_name // "ERROR"') + if [ "$tag" = "ERROR" ] || [ "$tag" = "null" ]; then + echo "ERROR: Could not get latest release tag for $repo" >&2 + echo "Response: $response" | head -3 >&2 + return 1 + fi + + echo "Latest release: $tag" >&2 + echo "$tag" +} + +# Function to safely list release assets +list_release_assets() { + local repo="$1" + local tag="$2" + echo + echo "=== Assets for $repo release $tag ===" + + local response + if [ -n "$GITHUB_TOKEN" ]; then + response=$(curl -s -H "$AUTH_HEADER" "https://api.github.com/repos/$repo/releases/tags/$tag") + else + response=$(curl -s "https://api.github.com/repos/$repo/releases/tags/$tag") + fi + + # Check if we got rate limited + if echo "$response" | jq -r '.message' 2>/dev/null | grep -q "rate limit"; then + echo "ERROR: GitHub API rate limit exceeded" + return 1 + fi + + # Extract asset names + local assets=$(echo "$response" | jq -r '.assets[]?.name // empty') + + if [ -z "$assets" ]; then + echo "ERROR: No assets found or API error" + echo "Response preview:" + echo "$response" | head -5 + return 1 + fi + + echo "Available assets:" + echo "$assets" | sort + echo + echo "Asset count: $(echo "$assets" | wc -l)" + echo +} + +# Function to show asset patterns used by setup-drivers.sh +show_current_patterns() { + echo "=== Current Asset Patterns in setup-drivers.sh ===" + echo + echo "Intel Graphics Compiler patterns:" + echo " - intel-igc-core.*amd64.deb" + echo " - intel-igc-opencl.*amd64.deb" + echo + echo "Intel Compute Runtime patterns:" + echo " - intel-ocloc_.*amd64.deb" + echo " - intel-ocloc-dbgsym.*amd64.ddeb" + echo " - libze-intel-gpu1-dbgsym.*amd64.ddeb" + echo " - libze-intel-gpu1_.*amd64.deb" + echo " - intel-opencl-icd-dbgsym.*amd64.ddeb" + echo " - intel-opencl-icd_.*amd64.deb" + echo " - libigdgmm12.*amd64.deb" + echo " - .*\.sum (checksum file)" + echo + echo "Intel NPU Driver patterns:" + echo " - linux-npu-driver.*ubuntu2404.tar.gz (contains individual .deb packages)" + echo + echo "Level Zero patterns:" + echo " - level-zero_.*u24.04.*amd64.deb" + echo +} + +# Function to test asset pattern matching +test_pattern_matching() { + local repo="$1" + local tag="$2" + local pattern="$3" + + echo "Testing pattern '$pattern' against $repo $tag:" + + local response + if [ -n "$GITHUB_TOKEN" ]; then + response=$(curl -s -H "$AUTH_HEADER" "https://api.github.com/repos/$repo/releases/tags/$tag") + else + response=$(curl -s "https://api.github.com/repos/$repo/releases/tags/$tag") + fi + local assets=$(echo "$response" | jq -r '.assets[]?.name // empty') + + local matches=$(echo "$assets" | grep -E "$pattern" || echo "") + + if [ -n "$matches" ]; then + echo " ✓ MATCHES FOUND:" + echo "$matches" | sed 's/^/ /' + else + echo " ✗ NO MATCHES" + echo " Available assets that might be relevant:" + echo "$assets" | grep -i "amd64\|\.deb\|\.ddeb" | head -5 | sed 's/^/ /' || echo " (none found)" + fi + echo +} + +# Function to collect asset URLs for static script generation +collect_asset_urls() { + local repo="$1" + local tag="$2" + + if [ "$BUILD_STATIC" = "false" ]; then + return 0 + fi + + echo "Collecting asset URLs for $repo $tag..." + + local response + if [ -n "$GITHUB_TOKEN" ]; then + response=$(curl -s -H "$AUTH_HEADER" "https://api.github.com/repos/$repo/releases/tags/$tag") + else + response=$(curl -s "https://api.github.com/repos/$repo/releases/tags/$tag") + fi + + # Check if we got rate limited or API error + if echo "$response" | jq -r '.message' 2>/dev/null | grep -q "rate limit"; then + echo "ERROR: GitHub API rate limit exceeded while collecting assets for $repo" >&2 + return 1 + fi + + # Check if response has assets + if ! echo "$response" | jq -e '.assets' >/dev/null 2>&1; then + echo "ERROR: No assets found in API response for $repo $tag" >&2 + echo "Response preview: $(echo "$response" | head -3)" >&2 + return 1 + fi + + # Store version + VERSIONS["$repo"]="$tag" + + # Extract download URLs based on repo + case "$repo" in + "intel/intel-graphics-compiler") + ASSET_URLS["igc-core"]=$(echo "$response" | jq -r '.assets[] | select(.name | test("intel-igc-core.*amd64\\.deb")) | .browser_download_url' | head -1) + ASSET_URLS["igc-opencl"]=$(echo "$response" | jq -r '.assets[] | select(.name | test("intel-igc-opencl.*amd64\\.deb")) | .browser_download_url' | head -1) + + # Validate required assets were found + if [ -z "${ASSET_URLS[igc-core]}" ] || [ "${ASSET_URLS[igc-core]}" = "null" ]; then + echo "ERROR: Could not find intel-igc-core asset for $repo $tag" >&2 + return 1 + fi + if [ -z "${ASSET_URLS[igc-opencl]}" ] || [ "${ASSET_URLS[igc-opencl]}" = "null" ]; then + echo "ERROR: Could not find intel-igc-opencl asset for $repo $tag" >&2 + return 1 + fi + ;; + "intel/compute-runtime") + ASSET_URLS["ocloc"]=$(echo "$response" | jq -r '.assets[] | select(.name | test("intel-ocloc_.*amd64\\.deb")) | .browser_download_url' | head -1) + ASSET_URLS["ocloc-dbgsym"]=$(echo "$response" | jq -r '.assets[] | select(.name | test("intel-ocloc-dbgsym.*amd64\\.ddeb")) | .browser_download_url' | head -1) + ASSET_URLS["ze-gpu-dbgsym"]=$(echo "$response" | jq -r '.assets[] | select(.name | test("libze-intel-gpu1-dbgsym.*amd64\\.ddeb")) | .browser_download_url' | head -1) + ASSET_URLS["ze-gpu"]=$(echo "$response" | jq -r '.assets[] | select(.name | test("libze-intel-gpu1_.*amd64\\.deb")) | .browser_download_url' | head -1) + ASSET_URLS["opencl-icd-dbgsym"]=$(echo "$response" | jq -r '.assets[] | select(.name | test("intel-opencl-icd-dbgsym.*amd64\\.ddeb")) | .browser_download_url' | head -1) + ASSET_URLS["opencl-icd"]=$(echo "$response" | jq -r '.assets[] | select(.name | test("intel-opencl-icd_.*amd64\\.deb")) | .browser_download_url' | head -1) + ASSET_URLS["igdgmm"]=$(echo "$response" | jq -r '.assets[] | select(.name | test("libigdgmm12.*amd64\\.deb")) | .browser_download_url' | head -1) + ASSET_URLS["checksum"]=$(echo "$response" | jq -r '.assets[] | select(.name | test(".*\\.sum")) | .browser_download_url' | head -1) + + # Validate required assets were found (checksum is optional) + local required_assets=("ocloc" "ocloc-dbgsym" "ze-gpu-dbgsym" "ze-gpu" "opencl-icd-dbgsym" "opencl-icd" "igdgmm") + for asset in "${required_assets[@]}"; do + if [ -z "${ASSET_URLS[$asset]}" ] || [ "${ASSET_URLS[$asset]}" = "null" ]; then + echo "ERROR: Could not find required asset '$asset' for $repo $tag" >&2 + return 1 + fi + done + ;; + "intel/linux-npu-driver") + # NPU drivers are now packaged as tar.gz files, find the Ubuntu 24.04 version + ASSET_URLS["npu-tarball"]=$(echo "$response" | jq -r '.assets[] | select(.name | test("linux-npu-driver.*ubuntu2404\\.tar\\.gz")) | .browser_download_url' | head -1) + + # Validate required asset was found + if [ -z "${ASSET_URLS[npu-tarball]}" ] || [ "${ASSET_URLS[npu-tarball]}" = "null" ]; then + echo "ERROR: Could not find required NPU tarball asset for $repo $tag" >&2 + return 1 + fi + ;; + "oneapi-src/level-zero") + ASSET_URLS["level-zero"]=$(echo "$response" | jq -r '.assets[] | select(.name | test("level-zero_.*u24\\.04.*amd64\\.deb")) | .browser_download_url' | head -1) + + # Validate required asset was found + if [ -z "${ASSET_URLS[level-zero]}" ] || [ "${ASSET_URLS[level-zero]}" = "null" ]; then + echo "ERROR: Could not find level-zero asset for $repo $tag" >&2 + return 1 + fi + ;; + esac + + echo "✓ Successfully collected assets for $repo" + return 0 +} + +# Function to generate static setup script +generate_static_setup_script() { + if [ "$BUILD_STATIC" = "false" ]; then + return 0 + fi + + echo "=== Generating setup-static-drivers.sh ===" + + # Validate that all required asset URLs are present before generating script + echo "Validating collected asset URLs..." + local required_assets=( + "igc-core" "igc-opencl" + "ocloc" "ocloc-dbgsym" "ze-gpu-dbgsym" "ze-gpu" "opencl-icd-dbgsym" "opencl-icd" "igdgmm" + "npu-tarball" + "level-zero" + ) + + local missing_assets=() + for asset in "${required_assets[@]}"; do + if [ -z "${ASSET_URLS[$asset]}" ] || [ "${ASSET_URLS[$asset]}" = "null" ]; then + missing_assets+=("$asset") + fi + done + + if [ ${#missing_assets[@]} -gt 0 ]; then + echo "ERROR: Missing required asset URLs: ${missing_assets[*]}" >&2 + echo "Cannot generate static script without all required assets" >&2 + return 1 + fi + + echo "✓ All required asset URLs validated" + + local static_script="setup-static-drivers.sh" + + # Create the static setup script + cat > "$static_script" << 'EOF' +#!/bin/bash + +# Copyright (C) 2025 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 +# +# Static Driver Setup Script - Generated by build-static-installer.sh +# This script uses exact filenames and wget to avoid GitHub API rate limits + +set -e + +# BKC +OS_ID="ubuntu" +OS_VERSION="24.04" +CURRENT_KERNEL_VERSION=$(uname -r) +# symbol +S_VALID="✓" + +# verify current user +if [ ! "$EUID" -eq 0 ]; then + echo "Please run with sudo or root user" + exit 1 +fi + +install_packages(){ + local PACKAGES=("$@") + local INSTALL_REQUIRED=0 + for PACKAGE in "${PACKAGES[@]}"; do + INSTALLED_VERSION=$(dpkg-query -W -f='${Version}' "$PACKAGE" 2>/dev/null || true) + LATEST_VERSION=$(apt-cache policy "$PACKAGE" | grep Candidate | awk '{print $2}') + + if [ -z "$INSTALLED_VERSION" ] || [ "$INSTALLED_VERSION" != "$LATEST_VERSION" ]; then + echo "$PACKAGE is not installed or not the latest version." + INSTALL_REQUIRED=1 + fi + done + if [ $INSTALL_REQUIRED -eq 1 ]; then + apt update + apt install -y "${PACKAGES[@]}" + fi +} + +verify_dependencies(){ + echo -e "# Verifying dependencies" + DEPENDENCIES_PACKAGES=( + git + clinfo + curl + wget + gpg-agent + libtbb12 + ) + install_packages "${DEPENDENCIES_PACKAGES[@]}" + echo "$S_VALID Dependencies installed" +} + +verify_intel_gpu_package_repo(){ + if [ ! -e /etc/apt/sources.list.d/intel-gpu-noble.list ]; then + echo "Adding Intel GPU repository" + wget -qO - https://repositories.intel.com/gpu/intel-graphics.key | \ + gpg --yes --dearmor --output /usr/share/keyrings/intel-graphics.gpg + echo "deb [arch=amd64,i386 signed-by=/usr/share/keyrings/intel-graphics.gpg] https://repositories.intel.com/gpu/ubuntu noble client" | \ + tee /etc/apt/sources.list.d/intel-gpu-noble.list + apt update + apt-get install -y libze-intel-gpu1 libze1 intel-opencl-icd clinfo intel-gsc + apt update + apt -y dist-upgrade + fi +} + +verify_igpu_driver(){ + echo -e "Verifying iGPU driver" + + if [ -z "$(clinfo | grep 'Driver Version' | awk '{print $NF}')" ] && [ ! -e /etc/apt/sources.list.d/intel-gpu-noble.list ]; then + verify_intel_gpu_package_repo + IGPU_PACKAGES=( + libze1 + intel-level-zero-gpu + intel-opencl-icd + clinfo + vainfo + hwinfo + ) + install_packages "${IGPU_PACKAGES[@]}" + FIRMWARE=(linux-firmware) + install_packages "${FIRMWARE[@]}" + + # $USER here is root + if ! id -nG "$USER" | grep -q -w '\'; then + echo "Adding current user ($USER) to 'video' group" + usermod -aG video "$USER" + fi + if ! id -nG "$USER" | grep -q '\'; then + echo "Adding current user ($USER) to 'render' group" + usermod -aG render "$USER" + fi + + # Get the native user who invoked sudo + NATIVE_USER="$(logname)" + + if ! id -nG "$NATIVE_USER" | grep -q -w '\'; then + echo "Adding native user ($NATIVE_USER) to 'video' group" + usermod -aG video "$NATIVE_USER" + fi + if ! id -nG "$NATIVE_USER" | grep -q '\'; then + echo "Adding native user ($NATIVE_USER) to 'render' group" + usermod -aG render "$NATIVE_USER" + fi + fi +} + +verify_os() { + echo -e "\n# Verifying operating system" + if [ ! -e /etc/os-release ]; then + echo "Error: /etc/os-release file not found" + exit 1 + fi + CURRENT_OS_ID=$(grep -E '^ID=' /etc/os-release | cut -d'=' -f2- | tr -d '"') + CURRENT_OS_VERSION=$(grep -E '^VERSION_ID=' /etc/os-release | cut -d'=' -f2- | tr -d '"') + if [ "$OS_ID" != "$CURRENT_OS_ID" ] || [ "$OS_VERSION" != "$CURRENT_OS_VERSION" ]; then + echo "Error: OS is not supported. Please make sure $OS_ID $OS_VERSION is installed" + exit 1 + fi + echo "$S_VALID OS version: $CURRENT_OS_ID $CURRENT_OS_VERSION" +} + +verify_gpu() { + echo -e "\n# Verifying GPU" + DGPU="$(lspci | grep VGA | grep Intel -c)" + + if [ "$DGPU" -ge 1 ]; then + if [ ! -e "/dev/dri" ]; then + IGPU=1 + else + IGPU="$(find /dev/dri -maxdepth 1 -type c -name 'renderD128*' | wc -l)" + fi + fi + if [ -e "/dev/dri" ]; then + IGPU="$(find /dev/dri -maxdepth 1 -type c -name 'renderD128*' | wc -l)" + fi + + if [ "$DGPU" -ge 2 ]; then + GPU_STAT_LABEL="- iGPU\n-dGPU (default)" + else + if [ "$IGPU" -lt 1 ]; then + GPU_STAT_LABEL="- n/a" + else + GPU_STAT_LABEL="- iGPU (default)" + fi + fi + echo -e "$GPU_STAT_LABEL" +} + +verify_kernel() { + echo -e "\n# Verifying kernel version" + CURRENT_KERNEL_VERSION=$(uname -r) + echo "$S_VALID Kernel version: $CURRENT_KERNEL_VERSION" + + # Check if running a recent enough kernel for Intel GPU/NPU support + KERNEL_MAJOR=$(echo "$CURRENT_KERNEL_VERSION" | cut -d'.' -f1) + KERNEL_MINOR=$(echo "$CURRENT_KERNEL_VERSION" | cut -d'.' -f2) + + if [ "$KERNEL_MAJOR" -lt 6 ] || ([ "$KERNEL_MAJOR" -eq 6 ] && [ "$KERNEL_MINOR" -lt 8 ]); then + echo "Warning: Kernel version $CURRENT_KERNEL_VERSION may not fully support Intel GPU/NPU drivers." + echo "Consider upgrading to kernel 6.8 or newer for optimal compatibility." + fi +} + +verify_platform() { + echo -e "\n# Verifying platform" + CPU_MODEL=$(< /proc/cpuinfo grep -m1 "model name" | cut -d: -f2 | sed 's/^[ \t]*//') + echo "- CPU model: $CPU_MODEL" +} + +EOF + + # Add version information with compatibility notes + cat >> "$static_script" << EOF +# Static asset URLs and versions (generated $(date)) +# Versions are compatibility-checked to prevent dependency conflicts +IGC_VERSION="${VERSIONS[intel/intel-graphics-compiler]}" +COMPUTE_RUNTIME_VERSION="${VERSIONS[intel/compute-runtime]}" +NPU_DRIVER_VERSION="${VERSIONS[intel/linux-npu-driver]}" +LEVEL_ZERO_VERSION="${VERSIONS[oneapi-src/level-zero]}" + +EOF + + # Add compatibility notice if there were warnings + if [ "$COMPATIBILITY_WARNING" = "true" ]; then + cat >> "$static_script" << 'EOF' +# WARNING: Version compatibility could not be fully verified during generation +# This script may encounter dependency conflicts during installation +# Test on a non-production system first + +EOF + else + cat >> "$static_script" << 'EOF' +# Version compatibility verified during generation +# These driver versions are known to work together without dependency conflicts + +EOF + fi + + # Add asset URLs with proper variable naming + for key in "${!ASSET_URLS[@]}"; do + # Convert key to uppercase and replace hyphens with underscores for bash variable names + var_name=$(echo "${key^^}" | tr '-' '_') + echo "ASSET_URL_${var_name}=\"${ASSET_URLS[$key]}\"" >> "$static_script" + done + + # Add the compute runtime function + cat >> "$static_script" << 'EOF' + +verify_compute_runtime(){ + echo -e "\n# Verifying Intel(R) Compute Runtime drivers" + + CURRENT_DIR=$(pwd) + + echo -e "Install Intel(R) Graphics Compiler version: $IGC_VERSION" + echo -e "Install Intel(R) Compute Runtime drivers version: $COMPUTE_RUNTIME_VERSION" + + if [ -d /tmp/neo_temp ];then + echo -e "Found existing folder in path /tmp/neo_temp. Removing the folder" + rm -rf /tmp/neo_temp + fi + + echo -e "Downloading compute runtime packages" + mkdir -p /tmp/neo_temp + cd /tmp/neo_temp + + # Download Intel Graphics Compiler packages + echo "Downloading IGC packages..." + wget "$ASSET_URL_IGC_CORE" || { echo "ERROR: Failed to download IGC core package"; exit 1; } + wget "$ASSET_URL_IGC_OPENCL" || { echo "ERROR: Failed to download IGC OpenCL package"; exit 1; } + + # Download Intel Compute Runtime packages + echo "Downloading Compute Runtime packages..." + wget "$ASSET_URL_OCLOC" || { echo "ERROR: Failed to download OCLOC package"; exit 1; } + wget "$ASSET_URL_OCLOC_DBGSYM" || { echo "WARNING: Failed to download OCLOC debug symbols"; } + wget "$ASSET_URL_ZE_GPU_DBGSYM" || { echo "WARNING: Failed to download ZE GPU debug symbols"; } + wget "$ASSET_URL_ZE_GPU" || { echo "ERROR: Failed to download ZE GPU package"; exit 1; } + wget "$ASSET_URL_OPENCL_ICD_DBGSYM" || { echo "WARNING: Failed to download OpenCL ICD debug symbols"; } + wget "$ASSET_URL_OPENCL_ICD" || { echo "ERROR: Failed to download OpenCL ICD package"; exit 1; } + wget "$ASSET_URL_IGDGMM" || { echo "ERROR: Failed to download IGDGMM package"; exit 1; } + + echo -e "Verify sha256 sums for packages (if available)" + if [ -n "$ASSET_URL_CHECKSUM" ]; then + wget "$ASSET_URL_CHECKSUM" || { echo "WARNING: Failed to download checksum file"; } + if [ -f "*.sum" ]; then + # Only verify checksums for files that actually exist + for file in *.deb *.ddeb; do + if [ -f "$file" ] && grep -q "$file" *.sum 2>/dev/null; then + echo "Verifying $file..." + sha256sum -c *.sum --ignore-missing || echo "Warning: Checksum verification failed for $file" + fi + done + else + echo "No checksum file available" + fi + else + echo "No checksum file found, skipping verification" + fi + + echo -e "\nInstalling compute runtime as root" + # Remove conflicting packages before installation + echo "Removing potentially conflicting packages..." + apt remove -y intel-ocloc libze-intel-gpu1 intel-level-zero-gpu intel-opencl-icd || true + dpkg --remove --force-remove-reinstreq intel-level-zero-gpu intel-ocloc libze-intel-gpu1 || true + apt --fix-broken install -y || true + + # Use dpkg with comprehensive conflict resolution + echo "Installing packages with comprehensive conflict resolution..." + dpkg -i --force-conflicts --force-depends --auto-deconfigure ./*.deb ./*.ddeb || { + echo "Installation failed, attempting recovery..." + apt --fix-broken install -y + dpkg -i --force-all ./*.deb ./*.ddeb + } + + cd .. + echo -e "Cleaning up /tmp/neo_temp folder after installation" + rm -rf neo_temp + cd "$CURRENT_DIR" +} + +verify_npu_driver(){ + echo -e "Verifying NPU drivers" + + CURRENT_DIR=$(pwd) + COMPILER_PKG=$(dpkg-query -l "intel-driver-compiler-npu" 2>/dev/null || true) + LEVEL_ZERO_PKG=$(dpkg-query -l "intel-level-zero-npu" 2>/dev/null || true) + + if [[ -z $COMPILER_PKG || -z $LEVEL_ZERO_PKG ]]; then + echo -e "NPU Driver is not installed. Proceed installing" + dpkg --purge --force-remove-reinstreq intel-driver-compiler-npu intel-fw-npu intel-level-zero-npu || true + apt install --fix-broken + apt update + + echo -e "Installing NPU Driver version: $NPU_DRIVER_VERSION" + echo -e "Installing Level Zero version: $LEVEL_ZERO_VERSION" + + if [ -d /tmp/npu_temp ];then + rm -rf /tmp/npu_temp + fi + + mkdir /tmp/npu_temp + cd /tmp/npu_temp + + # Download NPU driver tarball + echo "Downloading NPU driver tarball..." + wget "$ASSET_URL_NPU_TARBALL" -O npu-driver.tar.gz + + # Extract the tarball to get individual .deb packages + echo "Extracting NPU driver packages..." + tar -xzf npu-driver.tar.gz + + # Download Level Zero package + echo "Downloading Level Zero package..." + wget "$ASSET_URL_LEVEL_ZERO" + + # Install NPU packages (the .deb files are now extracted) + echo "Installing NPU packages..." + dpkg -i intel-driver-compiler-npu_*.deb intel-fw-npu_*.deb intel-level-zero-npu_*.deb level-zero_*.deb 2>/dev/null || { + echo "Installation failed, attempting with --force-depends..." + dpkg -i --force-depends intel-driver-compiler-npu_*.deb intel-fw-npu_*.deb intel-level-zero-npu_*.deb level-zero_*.deb + } + + cd .. + rm -rf npu_temp + cd "$CURRENT_DIR" + + # Set up device permissions for NPU + if [ -e /dev/accel/accel0 ]; then + chown root:render /dev/accel/accel0 + chmod g+rw /dev/accel/accel0 + fi + bash -c "echo 'SUBSYSTEM==\"accel\", KERNEL==\"accel*\", GROUP=\"render\", MODE=\"0660\"' > /etc/udev/rules.d/10-intel-vpu.rules" + udevadm control --reload-rules + udevadm trigger --subsystem-match=accel + fi +} + +verify_drivers(){ + echo -e "\n#Verifying drivers" + verify_igpu_driver + + # Check if GPU driver is properly installed + GPU_DRIVER_VERSION="$(clinfo | grep 'Driver Version' | awk '{print $NF}' 2>/dev/null || echo 'Not detected')" + if [ "$GPU_DRIVER_VERSION" = "Not detected" ]; then + echo "Warning: GPU driver not detected or clinfo not available" + else + echo "$S_VALID Intel GPU Drivers: $GPU_DRIVER_VERSION" + fi + + verify_npu_driver + + NPU_DRIVER_VERSION="$(sudo dmesg | grep vpu | awk 'NR==3{ print; }' | awk -F " " '{print $5" "$6" "$7}' 2>/dev/null || echo 'Not detected')" + if [ "$NPU_DRIVER_VERSION" = "Not detected" ]; then + echo "Warning: NPU driver not detected in dmesg" + else + echo "$S_VALID Intel NPU Drivers: $NPU_DRIVER_VERSION" + fi +} + +show_installation_summary(){ + echo -e "\n==================================================" + echo "# Intel AI PC Driver Installation Summary" + echo "==================================================" + echo "Date: $(date)" + echo "Kernel: $(uname -r)" + echo "OS: $(grep PRETTY_NAME /etc/os-release | cut -d'"' -f2 2>/dev/null || echo 'Unknown')" + echo + + echo "📦 DRIVER VERSIONS INSTALLED:" + echo "├─ Intel Graphics Compiler (IGC): $IGC_VERSION" + echo "├─ Intel Compute Runtime: $COMPUTE_RUNTIME_VERSION" + echo "├─ Intel NPU Driver: $NPU_DRIVER_VERSION" + echo "└─ Level Zero: $LEVEL_ZERO_VERSION" + echo + + echo "🔧 PACKAGES INSTALLED:" + echo "IGC Packages:" + echo "├─ intel-igc-core-2 (version: $(dpkg-query -W -f='${Version}' intel-igc-core-2 2>/dev/null || echo 'not installed'))" + echo "└─ intel-igc-opencl-2 (version: $(dpkg-query -W -f='${Version}' intel-igc-opencl-2 2>/dev/null || echo 'not installed'))" + echo + echo "Compute Runtime Packages:" + echo "├─ intel-ocloc (version: $(dpkg-query -W -f='${Version}' intel-ocloc 2>/dev/null || echo 'not installed'))" + echo "├─ libze-intel-gpu1 (version: $(dpkg-query -W -f='${Version}' libze-intel-gpu1 2>/dev/null || echo 'not installed'))" + echo "├─ intel-opencl-icd (version: $(dpkg-query -W -f='${Version}' intel-opencl-icd 2>/dev/null || echo 'not installed'))" + echo "└─ libigdgmm12 (version: $(dpkg-query -W -f='${Version}' libigdgmm12 2>/dev/null || echo 'not installed'))" + echo + echo "NPU Packages:" + echo "├─ intel-driver-compiler-npu (version: $(dpkg-query -W -f='${Version}' intel-driver-compiler-npu 2>/dev/null || echo 'not installed'))" + echo "├─ intel-fw-npu (version: $(dpkg-query -W -f='${Version}' intel-fw-npu 2>/dev/null || echo 'not installed'))" + echo "└─ intel-level-zero-npu (version: $(dpkg-query -W -f='${Version}' intel-level-zero-npu 2>/dev/null || echo 'not installed'))" + echo + echo "Level Zero Package:" + echo "└─ level-zero (version: $(dpkg-query -W -f='${Version}' level-zero 2>/dev/null || echo 'not installed'))" + echo + + echo "💻 HARDWARE STATUS:" + local gpu_info="$(lspci | grep VGA | grep Intel | head -1 | cut -d: -f3 | sed 's/^[ \t]*//' || echo 'No Intel GPU detected')" + echo "├─ GPU: $gpu_info" + local npu_info="$(lspci | grep -i 'neural\|npu\|vpu' | head -1 | cut -d: -f3 | sed 's/^[ \t]*//' || echo 'No NPU detected')" + echo "└─ NPU: $npu_info" + echo + + echo "📊 DRIVER STATUS:" + local gpu_driver_version="$(clinfo | grep 'Driver Version' | awk '{print $NF}' 2>/dev/null || echo 'Not detected')" + if [ "$gpu_driver_version" != "Not detected" ]; then + echo "├─ ✅ GPU Driver: $gpu_driver_version" + else + echo "├─ ⚠️ GPU Driver: Not detected (may need reboot)" + fi + + local npu_driver_info="$(dmesg | grep -i vpu | tail -1 | grep -o 'driver.*' 2>/dev/null || echo 'Not detected')" + if [ "$npu_driver_info" != "Not detected" ]; then + echo "└─ ✅ NPU Driver: Loaded" + else + echo "└─ ⚠️ NPU Driver: Not detected (may need reboot)" + fi + echo + + echo "🔗 VERIFICATION COMMANDS:" + echo "├─ GPU: clinfo | grep -E '(Device Name|Driver Version)'" + echo "├─ OpenCL: clinfo -l" + echo "├─ Level Zero: ls /sys/class/drm/renderD*" + echo "└─ NPU: dmesg | grep -i vpu" + echo + + echo "📝 NEXT STEPS:" + echo "1. Reboot the system if drivers are not detected" + echo "2. Add your user to 'video' and 'render' groups if not done:" + echo " sudo usermod -aG video,render \$USER" + echo + echo "==================================================" + echo "$S_VALID Intel AI PC Driver Installation Complete!" + echo "==================================================" +} + +setup(){ + echo "# Intel AI PC Linux Setup - Static Driver Installation" + echo "# This script uses pre-determined asset URLs to avoid GitHub API rate limits" + echo + + verify_dependencies + verify_platform + verify_gpu + verify_os + verify_drivers + verify_kernel + verify_compute_runtime + + echo -e "\n# Status" + echo "$S_VALID Platform configured" + + # Show comprehensive installation summary + show_installation_summary +} + +setup +EOF + + chmod +x "$static_script" + + echo "✓ Generated $static_script" + echo " - IGC Version: ${VERSIONS[intel/intel-graphics-compiler]}" + echo " - Compute Runtime Version: ${VERSIONS[intel/compute-runtime]}" + echo " - NPU Driver Version: ${VERSIONS[intel/linux-npu-driver]}" + echo " - Level Zero Version: ${VERSIONS[oneapi-src/level-zero]}" + echo + echo "Usage: sudo ./$static_script" +} + +# Function to download and inspect compute-runtime .deb for IGC dependencies +find_compatible_igc_version() { + local compute_runtime_tag="$1" + echo " Analyzing compute runtime $compute_runtime_tag for IGC dependencies..." >&2 + + # Create temporary directory for inspection + local temp_dir=$(mktemp -d) + cleanup() { rm -rf "$temp_dir"; } + trap cleanup EXIT + + # Get the compute runtime .deb download URL + local response + if [ -n "$GITHUB_TOKEN" ]; then + response=$(curl -s -H "$AUTH_HEADER" "https://api.github.com/repos/intel/compute-runtime/releases/tags/$compute_runtime_tag") + else + response=$(curl -s "https://api.github.com/repos/intel/compute-runtime/releases/tags/$compute_runtime_tag") + fi + + # Find intel-opencl-icd package (contains IGC dependency) + local opencl_icd_url=$(echo "$response" | jq -r '.assets[] | select(.name | test("intel-opencl-icd_.*amd64\\.deb$")) | .browser_download_url' | head -1) + + if [ -z "$opencl_icd_url" ] || [ "$opencl_icd_url" = "null" ]; then + echo " Could not find intel-opencl-icd package in compute runtime release" >&2 + return 1 + fi + + echo " Downloading package for dependency analysis..." >&2 + cd "$temp_dir" + + # Download the package + if ! wget -q "$opencl_icd_url"; then + echo " Failed to download package for analysis" >&2 + return 1 + fi + + local deb_file=$(basename "$opencl_icd_url") + + # Extract package control information + if ! dpkg-deb --field "$deb_file" Depends > depends.txt 2>/dev/null; then + echo " Failed to extract package dependencies" >&2 + return 1 + fi + + echo " Package dependencies:" >&2 + cat depends.txt >&2 + echo >&2 + + # Look for IGC dependency pattern - try multiple patterns + local igc_dep="" + + # Pattern 1: intel-igc-opencl (>= version) + igc_dep=$(grep -o 'intel-igc-opencl[[:space:]]*([^)]*' depends.txt 2>/dev/null | sed 's/.*(//' | sed 's/[[:space:]]*$//' || echo "") + + if [ -z "$igc_dep" ]; then + # Pattern 2: intel-igc-opencl = version + igc_dep=$(grep -o 'intel-igc-opencl[[:space:]]*=[[:space:]]*[^,[:space:]]*' depends.txt 2>/dev/null | sed 's/.*=[[:space:]]*//' || echo "") + fi + + if [ -z "$igc_dep" ]; then + # Pattern 3: Look for any intel-igc reference + igc_dep=$(grep -o 'intel-igc[^,[:space:]]*[[:space:]]*([^)]*' depends.txt 2>/dev/null | sed 's/.*(//' | sed 's/[[:space:]]*$//' || echo "") + fi + + if [ -z "$igc_dep" ]; then + echo " No specific IGC version dependency found" >&2 + return 1 + fi + + echo " Found IGC dependency: $igc_dep" >&2 + + # Extract version number from dependency (format: >= 1.0.15136.24) + local igc_version=$(echo "$igc_dep" | grep -o '[0-9][0-9.]*[0-9]' | head -1) + + if [ -z "$igc_version" ]; then + echo " Could not parse IGC version from dependency" >&2 + return 1 + fi + + echo "$igc_version" + return 0 +} + +# Function to find IGC GitHub tag matching a specific version +find_igc_tag_for_version() { + local required_version="$1" + echo " Searching for IGC tag matching version $required_version..." >&2 + + # Get list of IGC releases + local response + if [ -n "$GITHUB_TOKEN" ]; then + response=$(curl -s -H "$AUTH_HEADER" "https://api.github.com/repos/intel/intel-graphics-compiler/releases?per_page=50") + else + response=$(curl -s "https://api.github.com/repos/intel/intel-graphics-compiler/releases?per_page=50") + fi + + if [ -z "$response" ]; then + echo " Failed to get IGC releases" >&2 + return 1 + fi + + # Look for tags that contain or match the required version + local matching_tag=$(echo "$response" | jq -r ".[].tag_name" | grep -E "^(igc-|v)?${required_version}" | head -1) + + if [ -z "$matching_tag" ]; then + # Try more flexible matching - look for tags containing the version + matching_tag=$(echo "$response" | jq -r ".[].tag_name" | grep "$required_version" | head -1) + fi + + if [ -z "$matching_tag" ]; then + echo " No IGC tag found for version $required_version" >&2 + echo " Available recent tags:" >&2 + echo "$response" | jq -r ".[].tag_name" | head -5 | sed 's/^/ /' >&2 + return 1 + fi + + echo " Found matching IGC tag: $matching_tag" >&2 + echo "$matching_tag" + return 0 +} + +# Function to verify version compatibility between IGC and compute-runtime +check_version_compatibility() { + local igc_tag="$1" + local compute_runtime_tag="$2" + + echo " Cross-checking IGC $igc_tag with compute-runtime $compute_runtime_tag..." >&2 + + # Basic sanity check - make sure both tags exist and have releases + local igc_response + local cr_response + + if [ -n "$GITHUB_TOKEN" ]; then + igc_response=$(curl -s -H "$AUTH_HEADER" "https://api.github.com/repos/intel/intel-graphics-compiler/releases/tags/$igc_tag") + cr_response=$(curl -s -H "$AUTH_HEADER" "https://api.github.com/repos/intel/compute-runtime/releases/tags/$compute_runtime_tag") + else + igc_response=$(curl -s "https://api.github.com/repos/intel/intel-graphics-compiler/releases/tags/$igc_tag") + cr_response=$(curl -s "https://api.github.com/repos/intel/compute-runtime/releases/tags/$compute_runtime_tag") + fi + + # Check if both releases exist + local igc_exists=$(echo "$igc_response" | jq -r '.tag_name // "null"') + local cr_exists=$(echo "$cr_response" | jq -r '.tag_name // "null"') + + if [ "$igc_exists" = "null" ]; then + echo " IGC release $igc_tag not found" >&2 + return 1 + fi + + if [ "$cr_exists" = "null" ]; then + echo " Compute runtime release $compute_runtime_tag not found" >&2 + return 1 + fi + + # Check if both have assets (packages) + local igc_assets=$(echo "$igc_response" | jq -r '.assets[].name' | grep -c '\.deb$' || echo "0") + local cr_assets=$(echo "$cr_response" | jq -r '.assets[].name' | grep -c '\.deb$' || echo "0") + + if [ "$igc_assets" -eq 0 ]; then + echo " IGC release $igc_tag has no .deb packages" >&2 + return 1 + fi + + if [ "$cr_assets" -eq 0 ]; then + echo " Compute runtime release $compute_runtime_tag has no .deb packages" >&2 + return 1 + fi + + echo " ✓ Both releases exist and have packages" >&2 + + # Additional check: verify IGC release date is not too much newer than compute runtime + local igc_date=$(echo "$igc_response" | jq -r '.published_at') + local cr_date=$(echo "$cr_response" | jq -r '.published_at') + + if [ "$igc_date" != "null" ] && [ "$cr_date" != "null" ]; then + # Convert to timestamps for comparison (if available) + local igc_ts=$(date -d "$igc_date" +%s 2>/dev/null || echo "0") + local cr_ts=$(date -d "$cr_date" +%s 2>/dev/null || echo "0") + + if [ "$igc_ts" -gt 0 ] && [ "$cr_ts" -gt 0 ]; then + # Allow IGC to be up to 90 days newer than compute runtime + local max_diff=$((90 * 24 * 3600)) # 90 days in seconds + local time_diff=$((igc_ts - cr_ts)) + + if [ "$time_diff" -gt "$max_diff" ]; then + echo " Warning: IGC release is significantly newer than compute runtime" >&2 + echo " This may indicate version incompatibility" >&2 + return 1 + fi + fi + fi + + echo " ✓ Version compatibility checks passed" >&2 + return 0 +} + +# Function to check Level Zero compatibility with compute runtime +check_level_zero_compatibility() { + local compute_runtime_tag="$1" + local level_zero_tag="$2" + + echo " Checking Level Zero compatibility with compute runtime..." >&2 + + # Get compute runtime package to check for Level Zero dependencies + local response + if [ -n "$GITHUB_TOKEN" ]; then + response=$(curl -s -H "$AUTH_HEADER" "https://api.github.com/repos/intel/compute-runtime/releases/tags/$compute_runtime_tag") + else + response=$(curl -s "https://api.github.com/repos/intel/compute-runtime/releases/tags/$compute_runtime_tag") + fi + + # Find libze-intel-gpu1 package (may conflict with older Level Zero) + local ze_gpu_url=$(echo "$response" | jq -r '.assets[] | select(.name | test("libze-intel-gpu1_.*amd64\\.deb$")) | .browser_download_url' | head -1) + + if [ -z "$ze_gpu_url" ] || [ "$ze_gpu_url" = "null" ]; then + echo " No libze-intel-gpu1 package found in compute runtime release" >&2 + return 0 # No conflict possible + fi + + # Extract version from filename + local ze_gpu_version=$(echo "$ze_gpu_url" | grep -o 'libze-intel-gpu1_[^_]*' | cut -d'_' -f2) + + if [ -n "$ze_gpu_version" ]; then + echo " Found libze-intel-gpu1 version: $ze_gpu_version" >&2 + echo " This may conflict with older intel-level-zero-gpu packages" >&2 + echo " Recommendation: Remove intel-level-zero-gpu before installation" >&2 + fi + + return 0 +} + +# Collect compatible driver versions +collect_compatible_versions() { + echo "=== Collecting Compatible Driver Versions ===" + echo + + # First, get the latest compute runtime version + echo "📡 Getting latest compute runtime version..." + local compute_runtime_tag=$(get_latest_release_tag "intel/compute-runtime") + if [ $? -ne 0 ]; then + echo "❌ Failed to get compute runtime version" + return 1 + fi + echo " Latest compute runtime: $compute_runtime_tag" + + # Find compatible IGC version + echo "🔍 Finding compatible IGC version..." + local compatible_igc_version=$(find_compatible_igc_version "$compute_runtime_tag") + if [ $? -ne 0 ]; then + echo "⚠️ Could not determine compatible IGC version, using latest..." + COMPATIBLE_IGC_TAG=$(get_latest_release_tag "intel/intel-graphics-compiler") + COMPATIBILITY_WARNING="true" + echo " Using latest IGC: $COMPATIBLE_IGC_TAG" + else + echo " Required IGC version: $compatible_igc_version" + COMPATIBLE_IGC_TAG=$(find_igc_tag_for_version "$compatible_igc_version") + if [ $? -ne 0 ]; then + echo "⚠️ Could not find IGC tag for version $compatible_igc_version, using latest..." + COMPATIBLE_IGC_TAG=$(get_latest_release_tag "intel/intel-graphics-compiler") + COMPATIBILITY_WARNING="true" + else + echo " Found compatible IGC tag: $COMPATIBLE_IGC_TAG" + COMPATIBILITY_WARNING="false" + fi + fi + + # Get other component versions + COMPATIBLE_COMPUTE_RUNTIME_TAG="$compute_runtime_tag" + echo "📡 Getting NPU driver and Level Zero versions..." + COMPATIBLE_NPU_DRIVER_TAG=$(get_latest_release_tag "intel/linux-npu-driver") + COMPATIBLE_LEVEL_ZERO_TAG=$(get_latest_release_tag "oneapi-src/level-zero") + + echo + echo "📋 Selected versions:" + echo " IGC: $COMPATIBLE_IGC_TAG" + echo " Compute Runtime: $COMPATIBLE_COMPUTE_RUNTIME_TAG" + echo " NPU Driver: $COMPATIBLE_NPU_DRIVER_TAG" + echo " Level Zero: $COMPATIBLE_LEVEL_ZERO_TAG" + echo + + # Verify compatibility if we found a specific compatible version + if [ "$COMPATIBILITY_WARNING" = "false" ]; then + echo "🔍 Verifying compatibility..." + if check_version_compatibility "$COMPATIBLE_IGC_TAG" "$COMPATIBLE_COMPUTE_RUNTIME_TAG"; then + # Also check Level Zero compatibility + check_level_zero_compatibility "$COMPATIBLE_COMPUTE_RUNTIME_TAG" "$COMPATIBLE_LEVEL_ZERO_TAG" + echo "✅ All versions are compatible!" + return 0 + else + echo "❌ Version compatibility issues detected!" + COMPATIBILITY_WARNING="true" + fi + fi + + if [ "$COMPATIBILITY_WARNING" = "true" ]; then + echo "⚠️ WARNING: Could not verify version compatibility!" + echo " The generated static script may have dependency conflicts." + echo " Consider testing installation on a non-production system first." + echo " Recommendation: Use a GitHub token and retry, or test manually first." + fi + + return 0 +} + +# Main execution +echo "Checking GitHub API connectivity..." + +# Test basic API access +test_response="" +if [ -n "$GITHUB_TOKEN" ]; then + test_response=$(curl -s -H "$AUTH_HEADER" "https://api.github.com/rate_limit") +else + test_response=$(curl -s "https://api.github.com/rate_limit") +fi + +if ! echo "$test_response" | jq -r '.rate.remaining' > /dev/null; then + echo "ERROR: Cannot access GitHub API or jq parsing failed" + if [ "$BUILD_STATIC" = "true" ]; then + echo "Cannot generate static setup script without API access" + exit 1 + else + exit 1 + fi +fi + +echo "✓ GitHub API accessible" +echo + +# Check rate limit status +if [ -n "$GITHUB_TOKEN" ]; then + rate_info=$(curl -s -H "$AUTH_HEADER" "https://api.github.com/rate_limit") +else + rate_info=$(curl -s "https://api.github.com/rate_limit") +fi +remaining=$(echo "$rate_info" | jq -r '.rate.remaining') +limit=$(echo "$rate_info" | jq -r '.rate.limit') +reset_time=$(echo "$rate_info" | jq -r '.rate.reset') +reset_human=$(date -d "@$reset_time" 2>/dev/null || echo "unknown") + +echo "Rate limit status: $remaining/$limit requests remaining" +echo "Rate limit resets: $reset_human" + +if [ "$remaining" -lt 10 ]; then + echo "WARNING: Low rate limit remaining. Consider setting GITHUB_TOKEN" +fi +echo + +# Repository information +REPOS=("intel/intel-graphics-compiler" "intel/compute-runtime" "intel/linux-npu-driver" "oneapi-src/level-zero") + +# Arrays to store discovered assets for static script generation +declare -A ASSET_URLS +declare -A VERSIONS + +# Track errors for static script generation +STATIC_GENERATION_FAILED=false + +# Variables for compatibility checking +COMPATIBLE_IGC_TAG="" +COMPATIBLE_COMPUTE_RUNTIME_TAG="" +COMPATIBLE_NPU_DRIVER_TAG="" +COMPATIBLE_LEVEL_ZERO_TAG="" +COMPATIBILITY_WARNING="false" + +echo "=== Driver Version Verification ===" +echo "GitHub API token: ${GITHUB_TOKEN:+configured}" +echo "Mode: ${BUILD_STATIC:+Static script generation}${BUILD_STATIC:-Verification only}" +echo + +if [ "$BUILD_STATIC" = "true" ]; then + echo "🔧 Building static script with version compatibility checking..." + echo + + # Collect compatible versions + if ! collect_compatible_versions; then + echo "❌ Failed to get compatible versions" + echo "Cannot generate static setup script safely" + exit 1 + fi + + # Use compatible versions for repos + REPOS_VERSIONS=( + "intel/intel-graphics-compiler:$COMPATIBLE_IGC_TAG" + "intel/compute-runtime:$COMPATIBLE_COMPUTE_RUNTIME_TAG" + "intel/linux-npu-driver:$COMPATIBLE_NPU_DRIVER_TAG" + "oneapi-src/level-zero:$COMPATIBLE_LEVEL_ZERO_TAG" + ) + + echo "📦 Collecting assets for compatible versions..." + + for repo_version in "${REPOS_VERSIONS[@]}"; do + IFS=':' read -r repo tag <<< "$repo_version" + echo "----------------------------------------" + echo "Collecting assets for $repo $tag..." + + # Store version for later use + VERSIONS["$repo"]="$tag" + + # List assets for verification + if ! list_release_assets "$repo" "$tag"; then + echo "ERROR: Failed to list assets for $repo $tag" >&2 + STATIC_GENERATION_FAILED=true + continue + fi + + # Collect asset URLs + if ! collect_asset_urls "$repo" "$tag"; then + echo "ERROR: Failed to collect assets for $repo $tag" >&2 + STATIC_GENERATION_FAILED=true + fi + echo "----------------------------------------" + done +else + # Original verification mode - check latest versions + for repo in "${REPOS[@]}"; do + echo "----------------------------------------" + echo "Checking $repo..." + + # Get latest release tag + if tag=$(get_latest_release_tag "$repo"); then + echo "Latest release: $tag" + + # List all assets for debugging + list_release_assets "$repo" "$tag" + + # Test patterns only for compute-runtime (the problematic one) + if [ "$repo" = "intel/compute-runtime" ]; then + echo "=== Testing Current Patterns Against Actual Assets ===" + test_pattern_matching "$repo" "$tag" "intel-ocloc_.*amd64\.deb" + test_pattern_matching "$repo" "$tag" "libze-intel-gpu1-dbgsym.*amd64\.ddeb" + test_pattern_matching "$repo" "$tag" "libze-intel-gpu1_.*amd64\.deb" + test_pattern_matching "$repo" "$tag" "intel-opencl-icd-dbgsym.*amd64\.ddeb" + test_pattern_matching "$repo" "$tag" "intel-opencl-icd_.*amd64\.deb" + test_pattern_matching "$repo" "$tag" "libigdgmm12.*amd64\.deb" + fi + + # Test patterns for NPU driver + if [ "$repo" = "intel/linux-npu-driver" ]; then + echo "=== Testing NPU Driver Patterns Against Actual Assets ===" + test_pattern_matching "$repo" "$tag" "linux-npu-driver.*ubuntu2404\.tar\.gz" + fi + + # Test patterns for Level Zero + if [ "$repo" = "oneapi-src/level-zero" ]; then + echo "=== Testing Level Zero Patterns Against Actual Assets ===" + test_pattern_matching "$repo" "$tag" "level-zero_.*u24.04.*amd64\.deb" + fi + else + echo "Failed to get release information for $repo" + fi + echo "----------------------------------------" + done +fi + +show_current_patterns + +# Generate static setup script only if all assets were collected successfully +if [ "$BUILD_STATIC" = "true" ]; then + if [ "$STATIC_GENERATION_FAILED" = "true" ]; then + echo "" + echo "=== ERROR: Static Script Generation Failed ===" + echo "Cannot create setup-static-drivers.sh due to asset collection failures" >&2 + echo "Possible causes:" >&2 + echo "- GitHub API rate limiting (try setting GITHUB_TOKEN)" >&2 + echo "- Network connectivity issues" >&2 + echo "- Missing or moved driver assets in repositories" >&2 + echo "" >&2 + exit 1 + else + echo "" + echo "=== Generating Static Setup Script ===" + if [ "$COMPATIBILITY_WARNING" = "true" ]; then + echo "⚠️ WARNING: Version compatibility could not be fully verified" + echo " The generated script may have dependency conflicts" + echo " Test on a non-production system first" + echo "" + fi + + if generate_static_setup_script; then + echo "✅ Static setup script generated: setup-static-drivers.sh" + echo "" + echo "📋 Summary:" + echo " - IGC Version: ${VERSIONS[intel/intel-graphics-compiler]}" + echo " - Compute Runtime Version: ${VERSIONS[intel/compute-runtime]}" + echo " - NPU Driver Version: ${VERSIONS[intel/linux-npu-driver]}" + echo " - Level Zero Version: ${VERSIONS[oneapi-src/level-zero]}" + + if [ "$COMPATIBILITY_WARNING" = "false" ]; then + echo " - ✅ Version compatibility verified" + else + echo " - ⚠️ Version compatibility warning (see above)" + fi + + echo "" + echo "🚀 Usage: sudo ./setup-static-drivers.sh" + else + echo "❌ Failed to generate static setup script" + exit 1 + fi + fi +fi + +echo "" +echo "=== Summary ===" +echo "This diagnostic script completed safely without installing anything." +echo "Use the output above to:" +echo "1. Verify GitHub API connectivity" +echo "2. See what assets are actually available" +echo "3. Compare with patterns used in setup-drivers.sh" +echo "4. Identify any mismatched patterns that need updating" +if [ "$BUILD_STATIC" = "true" ] && [ "$STATIC_GENERATION_FAILED" = "false" ]; then + echo "5. ✓ Generated setup-static-drivers.sh with exact asset URLs" + echo -e " \033[1;32m Run: sudo ./setup-static-drivers.sh \033[0m" +fi diff --git a/Linux_Software_Installation/setup-software.sh b/Linux_Software_Installation/setup-software.sh new file mode 100644 index 0000000..0366cba --- /dev/null +++ b/Linux_Software_Installation/setup-software.sh @@ -0,0 +1,303 @@ +#!/bin/bash + +# Copyright (C) 2025 Intel Corporation +# SPDX-License-Identifier: MIT License + +set -e + +# symbol +S_VALID="✓" +CURRENT_DIRECTORY=$(pwd) + +# verify current user +if [ "$EUID" -eq 0 ]; then + echo "Must not run with sudo or root user" + exit 1 +fi + +install_packages(){ + local PACKAGES=("$@") + local INSTALL_REQUIRED=0 + for PACKAGE in "${PACKAGES[@]}"; do + INSTALLED_VERSION=$(dpkg-query -W -f='${Version}' "$PACKAGE" 2>/dev/null || true) + LATEST_VERSION=$(apt-cache policy "$PACKAGE" | grep Candidate | awk '{print $2}') + + if [ -z "$INSTALLED_VERSION" ] || [ "$INSTALLED_VERSION" != "$LATEST_VERSION" ]; then + echo "$PACKAGE is not installed or not the latest version." + INSTALL_REQUIRED=1 + fi + done + if [ $INSTALL_REQUIRED -eq 1 ]; then + sudo -E apt update + sudo -E apt install -y "${PACKAGES[@]}" + fi +} + +install_vulkan_sdk(){ + echo -e "\n# Installing Vulkan SDK" + # Add Vulkan repository key + wget -qO- https://packages.lunarg.com/lunarg-signing-key-pub.asc | sudo tee /etc/apt/trusted.gpg.d/lunarg.asc + + # Add Vulkan repository for Ubuntu 24.04 (Noble) + sudo wget -qO /etc/apt/sources.list.d/lunarg-vulkan-noble.list http://packages.lunarg.com/vulkan/lunarg-vulkan-noble.list + + # Update package list and install Vulkan SDK + sudo apt update + sudo apt install -y vulkan-sdk + + echo "$S_VALID Vulkan SDK installed" +} + +verify_dependencies(){ + echo -e "\n# Verifying dependencies" + DEPENDENCIES_PACKAGES=( + python3-pip + python3-venv + cmake + build-essential + pkg-config + git + curl + wget + ) + install_packages "${DEPENDENCIES_PACKAGES[@]}" + install_vulkan_sdk + echo "$S_VALID Dependencies installed" +} + +install_uv(){ + echo -e "\n# Installing UV" + if ! command -v uv &> /dev/null; then + wget -qO- https://astral.sh/uv/install.sh | sh + # Add UV to PATH for current session + export PATH="$HOME/.local/bin:$PATH" + # Verify installation + if command -v uv &> /dev/null; then + echo "$S_VALID UV installed successfully" + else + echo "Warning: UV installation may require a shell restart to update PATH" + fi + else + echo "$S_VALID UV is already installed" + fi +} + +install_openvino_notebook(){ + + echo -e "\n# Git clone OpenVINO™ notebooks" + if [ ! -d "./openvino_notebooks" ]; then + cd ~/intel + git clone https://github.com/openvinotoolkit/openvino_notebooks.git + cd openvino_notebooks + python3 -m venv venv + source venv/bin/activate + pip install -r requirements.txt + # Create ipykernel for this environment + pip install ipykernel + python -m ipykernel install --user --name=openvino_notebooks --display-name="OpenVINO Notebooks" + deactivate + else + echo "./openvino_notebooks already exists" + fi + echo -e "\n# Build OpenVINO™ notebook complete" +} + +install_openvino_notebook2(){ + + echo -e "\n# Git clone OpenVINO™ notebooks 2" + if [ ! -d "./openvino_build_deploy" ]; then + cd ~/intel + git clone https://github.com/openvinotoolkit/openvino_build_deploy.git + cd openvino_build_deploy/workshops/MSBuild2025 + python3 -m venv venv + source venv/bin/activate + pip install openvino==2025.3.0 ultralytics==8.3.120 + # Create ipykernel for this environment + pip install ipykernel + python -m ipykernel install --user --name=openvino_build_deploy --display-name="OpenVINO Build Deploy" + deactivate + else + echo "./openvino_build_deploy already exists" + fi + echo -e "\n# Build OpenVINO™ notebook2 complete" +} + +install_openvino_genai(){ + + echo -e "\n# OpenVINO™ GenAI" + if [ ! -d "./openvino_genai_ubuntu24_2025.3.0.0_x86_64" ]; then + cd ~/intel + curl -L https://storage.openvinotoolkit.org/repositories/openvino_genai/packages/2025.3/linux/openvino_genai_ubuntu24_2025.3.0.0_x86_64.tar.gz --output openvino_genai_2025.3.0.0.tgz + tar -xf openvino_genai_2025.3.0.0.tgz + + cd openvino_genai_u* + sudo -E ./install_dependencies/install_openvino_dependencies.sh + source setupvars.sh + cd samples/cpp + ./build_samples.sh + else + echo "./openvino_genai_ubuntu24_2025.3.0.0_x86_64 already exists" + fi + echo -e "\n# Build OpenVINO™ GenAI complete" +} + +install_llamacpp(){ + echo -e "\n# Install llama.cpp with Vulkan support" + + cd ~/intel + if [ ! -d "./llama.cpp" ]; then + # Check Vulkan support + echo "Checking Vulkan support..." + vulkaninfo + + # Clone and build llama.cpp with Vulkan support + git clone https://github.com/ggerganov/llama.cpp.git + cd llama.cpp + + # Build with Vulkan support + cmake -B build -DGGML_VULKAN=1 -DLLAMA_CURL=OFF + cmake --build build --config Release + + echo "$S_VALID llama.cpp native built with Vulkan support" + else + echo "llama.cpp already exists" + fi + + # Install llama-cpp-python with Vulkan support + echo -e "\n# Installing llama-cpp-python with Vulkan support" + if [ ! -d "./llamacpp_python_env" ]; then + cd ~/intel + python3 -m venv llamacpp_python_env + source llamacpp_python_env/bin/activate + + # Set environment variable for Vulkan support + export CMAKE_ARGS="-DGGML_VULKAN=ON -DLLAMA_CURL=OFF" + pip install llama-cpp-python + + # Create ipykernel for this environment + pip install ipykernel + python -m ipykernel install --user --name=llamacpp_python --display-name="LlamaCPP Python (Vulkan)" + deactivate + echo "$S_VALID llama-cpp-python installed with Vulkan support" + else + echo "llamacpp_python_env already exists" + fi + + echo -e "\n# llama.cpp installation complete" +} + +install_ollama(){ + + echo -e "\n# Install Ollama (regular version)" + cd ~/intel + + # Install regular Ollama using the official installer + curl -fsSL https://ollama.com/install.sh | sh + + # Start Ollama service + ollama serve & + sleep 5 + + # Pull a model for testing + ollama pull llama3.2:1b + + echo -e "\n# Ollama install complete" +} + +install_chrome(){ + + echo -e "\n# Install chrome" + cd ~/intel + wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb + sudo apt -y install ./google-chrome-stable_current_amd64.deb + echo -e "\n# chrome install complete" +} + +install_other_notebooks(){ + + echo -e "\n# Git clone Other notebooks " + if [ ! -d "./AI-PC-Samples" ]; then + cd ~/intel + git clone https://github.com/intel/AI-PC-Samples.git + + # Create virtual environment for AI-PC-Samples if it has requirements + if [ -f "./AI-PC-Samples/AI-Travel-Agent/requirements.txt" ]; then + cd AI-PC-Samples + python3 -m venv venv + source venv/bin/activate + pip install -r AI-Travel-Agent/requirements.txt + # Create ipykernel for this environment + pip install ipykernel + python -m ipykernel install --user --name=ai_pc_samples --display-name="AI PC Samples" + deactivate + cd .. + fi + else + echo "./AI-PC-Samples already exists" + fi + echo -e "\n# Clone other notebooks complete" +} + +install_vs_code(){ + + echo -e "\n# Install VS Code" + wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > packages.microsoft.gpg + sudo install -o root -g root -m 644 packages.microsoft.gpg /etc/apt/trusted.gpg.d/ + sudo sh -c 'echo "deb [arch=amd64 signed-by=/etc/apt/trusted.gpg.d/packages.microsoft.gpg] https://packages.microsoft.com/repos/vscode stable main" > /etc/apt/sources.list.d/vscode.list' + sudo apt update + sudo apt install code + echo -e "\n# VS Code complete" +} + +setup() { + if [ ! -d "/home/$(whoami)/intel" ]; then + echo "Creating ~/intel directory" + mkdir ~/intel + else + echo "~/intel already exists" + fi + cd ~/intel + verify_dependencies + install_uv + install_openvino_notebook + install_openvino_notebook2 + install_openvino_genai + install_llamacpp + install_ollama + install_chrome + install_other_notebooks + install_vs_code + + echo -e "\n# Status" + echo "$S_VALID AI PC DevKit Installed" + echo -e "\nInstalled Jupyter kernels:" + echo "- OpenVINO Notebooks" + echo "- OpenVINO Build Deploy" + echo "- LlamaCPP Python (Vulkan)" + echo "- AI PC Samples (if AI-Travel-Agent/requirements.txt exists)" + echo -e "\nTo list all available kernels, run: jupyter kernelspec list" + + echo -e "\n# Virtual Environment Activation Commands" + echo "To activate each virtual environment, use the following commands:" + echo "" + echo "1. OpenVINO Notebooks:" + echo " cd ~/intel/openvino_notebooks && source venv/bin/activate" + echo "" + echo "2. OpenVINO Build Deploy:" + echo " cd ~/intel/openvino_build_deploy/workshops/MSBuild2025 && source venv/bin/activate" + echo "" + echo "3. LlamaCPP Python (Vulkan):" + echo " cd ~/intel && source llamacpp_python_env/bin/activate" + echo "" + if [ -d "./AI-PC-Samples" ] && [ -f "./AI-PC-Samples/AI-Travel-Agent/requirements.txt" ]; then + echo "4. AI PC Samples:" + echo " cd ~/intel/AI-PC-Samples && source venv/bin/activate" + echo "" + fi + echo "5. OpenVINO GenAI (setup environment variables):" + echo " cd ~/intel/openvino_genai_u* && source setupvars.sh" + echo "" + echo "Note: To deactivate any virtual environment, simply run: deactivate" +} + +setup diff --git a/README.md b/README.md index 2010820..408886b 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,238 @@ -# New SDK Installer Coming Soon! +# AIPC Application Installer Version v2.0 -* We are excited to announce that a new SDK installer is currently in development and will be available soon. This new installer aims to enhance the user experience by providing a more streamlined and efficient installation process. \ No newline at end of file +## Introduction + +Welcome to the AIPC Application Installer. This application is specifically designed to facilitate the setup of development tools, apps and environments for the Intel AIPC Developer engagements and events. It leverages the Microsoft package manager, winget, and can also download external applications using curl with additional configuration as listed below + +**Note**:- If you have any existing applications already installed, please uninstall them first and then use this utility to install. Installing the same application in two different ways may cause conflicts and the application may not work as expected. User discretion is mandatory. + +**New in v2.0:** + +- **Interactive GUI Mode**: Windows Forms interface + + Integrated Install: Visual interface for for visual package selection and installation + Integrated Uninstall: Visual interface for visual package uninstall of previously installed packages +- **Enhanced JSON Structure**: Improved package descriptions with friendly names and summaries +- **Advanced Exit Code Handling**: Robust error detection and handling for both install and uninstall operations +- **Automatic Administrator Privileges**: Smart detection and elevation requests for all operations +- **Real-time Package Tracking**: Automatic tracking of installed packages for future uninstallation +- **Backward Compatibility**: Works with both new and legacy JSON formats + +## Key Features + +### Smart Package Management +- **Automatic Tracking**: Installed packages are tracked for easy uninstallation +- **Duplicate Prevention**: Won't install already installed packages +- **Dependency Resolution**: Handles package dependencies automatically + +### Enhanced User Experience +- **Visual Interface**: Windows Forms GUI for easy interaction +- **Detailed Feedback**: Clear success/failure messages with exit code information +- **Error Recovery**: Graceful handling of various installation scenarios + +### Robust Operation +- **Exit Code Intelligence**: Recognizes various success/failure conditions +- **Administrator Handling**: Automatic privilege detection and elevation +- **Logging**: Comprehensive logging for troubleshooting + + +For any assistance, please refer to the support documentation or contact our technical support team. + +## Quick Start + +### Pre-requisites +- **Administrator Privileges**: The script will automatically check and request administrator privileges when needed +- **PowerShell Execution Policy**: Set to Unrestricted (the script will guide you) +- **Winget**: Must be installed with version 1.10.X or higher + + + +### Step 1: Set Execution Policy +```powershell +Set-ExecutionPolicy -ExecutionPolicy Unrestricted LocalMachine +``` + +### Step 2: Run the First Setup Script +Navigate to the following directory and run the initial environment setup script: +```powershell +cd Windows_Software_Installation\WingetGUI_Installer +.\Setup_1.ps1 gui #Install/Uninstall using GUI Mode +.\Setup_1.ps1 install #Install using commandline +.\Setup_1.ps1 uninstall #UnInstall using commandline +``` +GUI Mode opens the Windows Forms interface for interactive package selection and installation/uninstallation. + +### Step 3: Reboot the Machine +After completing the environment setup, reboot your machine to ensure all changes take effect and new environments are recognized. + +### Step 4: Run the Second Setup Script +```powershell +cd Windows_Software_Installation\WingetGUI_Installer +.\Setup_2.ps1 +``` +This will pull a number of repositories and build the necessary environments to execute the samples. + +## Options Internal vs External + +Internal Mode + +- Silent Operation: In internal mode, the script runs silently in the background, automatically accepting all license agreements. + Module Installation: Installs the PowerShell module WingetClient and updates winget to the latest version 1.10.390. + +External Mode +-Silent Operation but with User Interaction: In external mode, users must manually accept pop-up agreements before utilizing the application. + +## Pre-requisites to run script + + +Administrator Privileges: Ensure the "powershell" terminal is running in admin mode. + +- Example `Set-ExecutionPolicy -ExecutionPolicy Unrestricted LocalMachine` + +- `winget` must be installed on computer with latest version 1.10.X or higher + Winget Installation version verification use command: `winget --version` + If not installed, execute + Install-Module -Name Microsoft.WinGet.Client + Repair-WinGetPackageManager -Force -Latest +- Ensure you have the latest version `1.10.X` + +- For every application installed a corresponding entry is created in `JSON\uninstall\uninstall.json`, once you have winget installed execute the script using `.\Setup_1.ps1 install` + + + +#### Global Install Flags + +- `global_install_flags` + - These are run for `winget`. The pre included ones are: + - `--silent` Allows it to run in the background + - `--accept-package-agreements` and `--accept-source-agreements` Allows it to run via task scheduler without having UAC pop ups + - `--disable-interactivity` Another fallback to remove UAC agreements + - `--force` Final check to ensure things resolve and install + +### Applications JSON Structure +- **JSON Configuration**: [Windows_Software_Installation/WingetGUI_Installer/JSON/install/applications.json](./Windows_Software_Installation/WingetGUI_Installer/JSON/install/applications.json) + +Winget Applications +Applications installed via the Windows package manager, with automatic dependency resolution: + + { + + + "id": "Microsoft.VisualStudioCode", + "friendly_name": "Visual Studio Code", + "summary": "Code editor", + "override_flags": null, + "install_location": null, + "version": null, + "version_check": null, + "dependencies": null, + "skip_install": "no" + } + +External Applications +Applications not installed via the Windows package manager, requiring a URL for download via curl + + { + "name": "one_api_base_toolkit", + "source": "https://install_url/application.exe", + "install_flags": "--some --exes --want --install --flags", + "download_location": "C:\\Required\\download\\location", + "uninstall_command": "C:\\Required\\download\\location\\uninstaller.exe", + "dependencies": [ + { + "name": "Optional Dependency" + }, + { + "name": "Visual Studio Code" + }, + { + "name": "C++ Redistribution" + } + ] + } + +Notes:- +Installation Order: The installation process executes from top to bottom. It is recommended to place external applications and items with dependencies last to ensure required software is installed first. +OneAPI Base Toolkit: This toolkit requires specific dependencies, including Visual Studio Community and .NET and C++ frameworks. For easy uninstallation, include the uninstall command, typically formatted as: +C:\Program Files (x86)\Intel\oneAPI\Installer\installer.exe -s --action remove --product-id intel.oneapi.win.basekit.product --product-ver 2025.0.1+44 + +"skip_install": "no" --indicates this is a mandatory install even if application is part of JSON, please set this to "yes" if you dont want this application to be installed by default. + +To find the specific product version, execute: +.\installer.exe --list-products + +#### Workflow Overview + +1. Administrator Privileges Check: Verifies admin access. +2. Execution Policy Setting: Sets policy to Unrestricted. +3. Application List Reading: Reads from applications.json. +4. Log Directory Initialization: Prepares logging environment. +5. Application Identification: Determines applications for installation. +6. Installation and Logging: Installs applications and logs the process. +7. Uninstall JSON Creation: Generates a file for tracking installed applications. + +**Applications Configuration** + +**applications.json Overview** +The applications.json file configures applications for installation by the Setup_1.ps1 script, detailing Winget and external applications along with their installation parameters. + +**VerifyInstall** + +1. This script performs a basic command line version check with the specified tool. + +- Global Install Flags: Default flags for all installations. +- Winget Applications: Array of Winget applications to be installed. +- External Applications: Array of external applications to be installed. + +Adding New Applications to installer +To add an application, first verify its availability via winget: +Example: + +#### Overview + +- Reads application list from `applications.json` +- Installs Winget applications and external applications +- Logs installation process +- Creates an uninstall JSON file for tracking installed applications + +#### Workflow + +1. Checks for administrator privileges +2. Sets execution policy to Unrestricted +3. Reads application list from `applications.json` +4. Initializes log directory +5. Identifies applications that need to be installed +6. Installs each application and logs the process +7. Creates an uninstall JSON file for tracking installed applications + +### applications.json + +#### Overview + +The `applications.json` file contains the configuration for applications to be installed by the `Setup_1.ps1` script. It includes a list of Winget applications and external applications, along with their installation parameters. + +#### VerifyInstall + +This script runs a basic command line version check with the specified tool + +##### Root Object + +- `global_install_flags` (string): Default flags for all installations +- `winget_applications` (array): List of Winget applications to be installed +- `external_applications` (array): List of external applications to be installed + + ## Opens/Issues + +- Uninstall of Clink and Microsoft Visual Studio Installer does not have a silent and suppress window method, user interaction is required. There is no available solution with winget and will be resolved when the software vendor releases a patch.This is not a blocker and functionality of this installer is not hampered in anyway. +- If python is installed please make sure Python is added to the system's PATH environment variable. This step is manual and not part of installation + +## Documentation + +For detailed documentation, configuration guides, and troubleshooting: +- **Windows Installer Documentation**: [Windows_Software_Installation/README.md](./Windows_Software_Installation/README.md) + +## Support + +For technical assistance, configuration help, or feature requests: +- Contact: Ram (vaithi.s.ramadoss@intel.com) or Vijay (vijay.chandrashekar@intel.com) +- Full documentation: [Windows_Software_Installation/README.md](./Windows_Software_Installation/README.md) diff --git a/Windows_Software_Installation/OVMS/README_OVMS.md b/Windows_Software_Installation/OVMS/README_OVMS.md new file mode 100644 index 0000000..291d914 --- /dev/null +++ b/Windows_Software_Installation/OVMS/README_OVMS.md @@ -0,0 +1,134 @@ +# OVMS Launcher + +A PowerShell script that downloads, configures, and starts OpenVINO Model Server. + +## Quick Start + +```powershell +# Start text model on GPU (default) +.\ovms_setup.ps1 + +# Start text model on CPU +.\ovms_setup.ps1 -Target CPU + +# Start text model on NPU (Intel AI PC) +.\ovms_setup.ps1 -Target NPU + +# Start image generation on GPU +.\ovms_setup.ps1 -Model image + +# Start custom model +.\ovms_setup.ps1 -Model "OpenVINO/Mistral-7B-Instruct-v0.2-int4-cw-ov" -Target NPU +``` + +## Features + +- **One Command**: Downloads OVMS, downloads models, starts server +- **Smart Defaults**: Automatically selects best model for each device +- **Auto Download**: Models download automatically from Hugging Face +- **Device Optimized**: Different models optimized for GPU/CPU/NPU + +## Default Models + +### Text Generation +- **GPU/CPU**: `OpenVINO/Phi-3.5-mini-instruct-int4-ov` +- **NPU**: `OpenVINO/Phi-3.5-mini-instruct-int4-cw-ov` (NPU-optimized) + +### Image Generation +- **GPU**: `OpenVINO/FLUX.1-schnell-int4-ov` +- **CPU**: `OpenVINO/stable-diffusion-v1-5-int8-ov` + +## Parameters + +- `-Model`: "text" (default), "image", or full OpenVINO model name +- `-Target`: "GPU" (default), "CPU", or "NPU" +- `-Port`: REST API port (default: 8000) +- `-Help`: Show detailed help message + +## Getting Help + +The script includes comprehensive help options: + +```powershell +# Show built-in help with examples +.\ovms_setup.ps1 -Help + +# PowerShell native help +Get-Help .\ovms_setup.ps1 +Get-Help .\ovms_setup.ps1 -Examples +Get-Help .\ovms_setup.ps1 -Detailed +``` + +## Examples + +```powershell +# Basic usage +.\ovms_setup.ps1 # Phi-3 on GPU +.\ovms_setup.ps1 -Target CPU # Phi-3 on CPU +.\ovms_setup.ps1 -Target NPU # Phi-3 on NPU +.\ovms_setup.ps1 -Model image # FLUX on GPU + +# Custom models +.\ovms_setup.ps1 -Model "OpenVINO/gpt-j-6b-int4-cw-ov" -Target NPU +.\ovms_setup.ps1 -Model "OpenVINO/stable-diffusion-v1-5-fp16-ov" -Target GPU +.\ovms_setup.ps1 -Model "OpenVINO/Mistral-7B-Instruct-v0.2-int4-cw-ov" -Target CPU + +# Custom port +.\ovms_setup.ps1 -Port 9000 +``` + +## API Access + +Once started, the API is available at: `http://localhost:8000/v3` + +### Test with curl: +```bash +(Invoke-WebRequest -Uri "http://localhost:8000/v3/chat/completions" ` + -Method POST ` + -Headers @{ "Content-Type" = "application/json" } ` + -Body '{"model": "OpenVINO/Phi-3.5-mini-instruct-int4-ov", "max_tokens": 30, "temperature": 0, "stream": false, "messages": [{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "What are the 3 main tourist attractions in Paris?"}]}').Content + +``` + +### Test with Python: +```python +from openai import OpenAI + +client = OpenAI( + base_url="http://localhost:8000/v3", + api_key="unused" +) + +response = client.chat.completions.create( + model="OpenVINO/Phi-3.5-mini-instruct-int4-ov", + messages=[{"role": "user", "content": "Hello!"}], + max_tokens=50 +) + +print(response.choices[0].message.content) +``` + +## What It Does + +1. **Downloads OVMS**: Automatically downloads OpenVINO Model Server v2025.2.1 if not present +2. **Initializes Environment**: Runs setupvars.ps1 to properly configure OpenVINO environment +3. **Selects Model**: Chooses the best model for your target device +4. **Downloads Model**: Downloads the model from Hugging Face Hub automatically +5. **Starts Server**: Launches OVMS with optimal parameters for the model type +6. **Ready to Use**: API available immediately at the specified port + +## Requirements + +- Windows PowerShell 5.1+ or PowerShell Core 7+ +- Internet connection (for downloads) +- For NPU: Intel AI PC with NPU drivers + +## Device Recommendations + +- **GPU**: Fastest performance, best for production +- **CPU**: Works everywhere, good for development +- **NPU**: power efficient + +## Stop Server + +Press `Ctrl+C` to stop the server. diff --git a/Windows_Software_Installation/OVMS/ovms_setup.ps1 b/Windows_Software_Installation/OVMS/ovms_setup.ps1 new file mode 100644 index 0000000..9393da0 --- /dev/null +++ b/Windows_Software_Installation/OVMS/ovms_setup.ps1 @@ -0,0 +1,289 @@ +#!/usr/bin/env powershell +<# +.SYNOPSIS + Simple One-Command OVMS Script - Download and Start Models (v2025.3 Compatible) + +.DESCRIPTION + Downloads OVMS v2025.3, downloads models, and starts the server in one command. + Supports GPU/CPU/NPU devices with automatic model selection and required task parameters. + +.PARAMETER Model + Model type: "text" (default), "image", or full OpenVINO model name + +.PARAMETER Target + Target device: "GPU" (default), "CPU", or "NPU" + +.PARAMETER Port + REST API port (default: 8000) + +.EXAMPLE + .\start_ovms_simple_v2025.3.ps1 + # Starts Phi-3 text model on GPU + +.EXAMPLE + .\start_ovms_simple_v2025.3.ps1 -Target NPU + # Starts NPU-optimized Phi-3 on NPU + +.EXAMPLE + .\start_ovms_simple_v2025.3.ps1 -Model image + # Starts FLUX image generation on GPU + +.EXAMPLE + .\start_ovms_simple_v2025.3.ps1 -Model "OpenVINO/Mistral-7B-Instruct-v0.2-int4-cw-ov" -Target CPU + # Starts custom model on CPU +#> + +param( + [string]$Model = "text", + [ValidateSet("GPU", "CPU", "NPU")] + [string]$Target = "GPU", + [int]$Port = 8000, + [switch]$Help +) + +# Color output functions +function Write-Info { param([string]$Message) Write-Host "[INFO] $Message" -ForegroundColor Cyan } +function Write-Success { param([string]$Message) Write-Host "[OK] $Message" -ForegroundColor Green } +function Write-Warning { param([string]$Message) Write-Host "[WARN] $Message" -ForegroundColor Yellow } +function Write-Error { param([string]$Message) Write-Host "[ERROR] $Message" -ForegroundColor Red } + +# Default models for each device +$DefaultModels = @{ + "GPU" = @{ + "text" = "OpenVINO/Phi-3.5-mini-instruct-int4-ov" + "image" = "OpenVINO/FLUX.1-schnell-int4-ov" + } + "CPU" = @{ + "text" = "OpenVINO/Phi-3.5-mini-instruct-int4-ov" + "image" = "OpenVINO/stable-diffusion-v1-5-int8-ov" + } + "NPU" = @{ + "text" = "OpenVINO/Phi-3.5-mini-instruct-int4-cw-ov" + "image" = "OpenVINO/FLUX.1-schnell-int8-ov" + } +} + +function Get-SourceModel { + param([string]$ModelInput, [string]$TargetDevice) + + # If it's a shorthand, resolve to full model name + if ($ModelInput -eq "text" -or $ModelInput -eq "image") { + return $DefaultModels[$TargetDevice][$ModelInput] + } + + # If it's already a full model name, return as-is + return $ModelInput +} + +function Get-ModelTask { + param([string]$SourceModel) + + # Determine task type based on model name patterns + $imageModelPatterns = @( + "*FLUX*", + "*flux*", + "*diffusion*", + "*Dreamshaper*", + "*SDXL*", + "*stable-diffusion*", + "*controlnet*", + "*text-to-image*", + "*image-generation*" + ) + + foreach ($pattern in $imageModelPatterns) { + if ($SourceModel -like $pattern) { + return "image_generation" + } + } + + # Default to text generation for all other models + return "text_generation" +} + +function Initialize-OVMS { + Write-Info "Setting up OVMS..." + + $ovmsDir = "ovms" + $ovmsExe = Join-Path $ovmsDir "ovms.exe" + + if (Test-Path $ovmsExe) { + Write-Success "OVMS already available" + + # Always run setupvars to ensure environment is properly initialized + $setupVars = Join-Path $ovmsDir "setupvars.ps1" + if (Test-Path $setupVars) { + Write-Info "Initializing OpenVINO Model Server environment..." + try { + $setupOutput = & $setupVars 2>&1 + if ($setupOutput -like "*Environment Initialized*") { + Write-Success "OpenVINO Model Server Environment Initialized" + } else { + Write-Info "Environment setup completed" + } + } + catch { + Write-Warning "Environment setup had issues, but continuing..." + } + } + + return $ovmsExe + } + + Write-Info "Downloading OVMS v2025.3...." + $ovmsUrl = "https://github.com/openvinotoolkit/model_server/releases/download/v2025.3/ovms_windows_python_on.zip" + $ovmsZip = "ovms.zip" + + try { + Invoke-WebRequest -Uri $ovmsUrl -OutFile $ovmsZip -UseBasicParsing + Expand-Archive -Path $ovmsZip -DestinationPath "." -Force + Remove-Item $ovmsZip -Force -ErrorAction SilentlyContinue + + if (Test-Path $ovmsExe) { + Write-Success "OVMS downloaded and extracted" + + # Run setupvars to initialize environment + $setupVars = Join-Path $ovmsDir "setupvars.ps1" + if (Test-Path $setupVars) { + Write-Info "Initializing OpenVINO Model Server environment..." + try { + $setupOutput = & $setupVars 2>&1 + if ($setupOutput -like "*Environment Initialized*") { + Write-Success "OpenVINO Model Server Environment Initialized" + } else { + Write-Info "Environment setup completed" + } + } + catch { + Write-Warning "Environment setup had issues, but continuing..." + } + } + + return $ovmsExe + } else { + throw "OVMS extraction failed" + } + } + catch { + Write-Error "Failed to setup OVMS: $_" + exit 1 + } +} + +function Start-OVMSServer { + param([string]$SourceModel, [string]$TargetDevice, [int]$RestPort) + + Write-Info "Starting OVMS Server..." + Write-Info "Model: $SourceModel" + Write-Info "Target: $TargetDevice" + Write-Info "Port: $RestPort" + Write-Success "API will be available at: http://localhost:$RestPort/v3" + Write-Info "" + + # Ensure models directory exists + if (-not (Test-Path "models")) { + New-Item -ItemType Directory -Path "models" -Force | Out-Null + } + + # Determine the task type for the model + $taskType = Get-ModelTask -SourceModel $SourceModel + + Write-Info "Detected task type: $taskType" + Write-Info "Starting server (model will download automatically if not cached)..." + Write-Warning "Press Ctrl+C to stop the server" + Write-Info "" + + try { + if ($taskType -eq "image_generation") { + Write-Info "Using image generation mode with --task image_generation..." + & ".\ovms\ovms.exe" --rest_port $RestPort --model_repository_path "models" --task image_generation --source_model $SourceModel --target_device $TargetDevice --log_level INFO + } else { + Write-Info "Using text generation mode with --task text_generation..." + & ".\ovms\ovms.exe" --source_model $SourceModel --model_repository_path "models" --rest_port $RestPort --target_device $TargetDevice --task text_generation --cache_size 4 --log_level INFO + } + } + catch { + Write-Error "Failed to start OVMS server: $_" + exit 1 + } +} + +# Main execution +Write-Info "Simple OVMS Launcher (v2025.3 Compatible)" +Write-Info "==========================================" + +# Show help if requested +if ($Help) { + Write-Host "" + Write-Host "Simple OVMS Launcher - One Command Setup (v2025.3 Compatible)" -ForegroundColor Yellow + Write-Host "=============================================================" -ForegroundColor Yellow + Write-Host "" + Write-Host "USAGE:" -ForegroundColor Green + Write-Host " .\start_ovms_simple_v2025.3.ps1 [-Model ] [-Target ] [-Port ]" -ForegroundColor White + Write-Host "" + Write-Host "PARAMETERS:" -ForegroundColor Green + Write-Host " -Model : 'text' (default), 'image', or full OpenVINO model name" -ForegroundColor White + Write-Host " -Target : 'GPU' (default), 'CPU', or 'NPU'" -ForegroundColor White + Write-Host " -Port : REST API port (default: 8000)" -ForegroundColor White + Write-Host " -Help : Show this help message" -ForegroundColor White + Write-Host "" + Write-Host "NEW IN v2025.3:" -ForegroundColor Green + Write-Host " • Automatic task detection (--task text_generation or --task image_generation)" -ForegroundColor White + Write-Host " • Enhanced model pattern recognition for task assignment" -ForegroundColor White + Write-Host " • Required task parameters for all model types" -ForegroundColor White + Write-Host "" + Write-Host "EXAMPLES:" -ForegroundColor Green + Write-Host " .\start_ovms_simple_v2025.3.ps1" -ForegroundColor Cyan + Write-Host " # Start Phi-3 text model on GPU with --task text_generation" -ForegroundColor Gray + Write-Host "" + Write-Host " .\start_ovms_simple_v2025.3.ps1 -Target CPU" -ForegroundColor Cyan + Write-Host " # Start Phi-3 text model on CPU with --task text_generation" -ForegroundColor Gray + Write-Host "" + Write-Host " .\start_ovms_simple_v2025.3.ps1 -Target NPU" -ForegroundColor Cyan + Write-Host " # Start NPU-optimized Phi-3 on NPU with --task text_generation" -ForegroundColor Gray + Write-Host "" + Write-Host " .\start_ovms_simple_v2025.3.ps1 -Model image" -ForegroundColor Cyan + Write-Host " # Start FLUX image generation on GPU with --task image_generation" -ForegroundColor Gray + Write-Host "" + Write-Host " .\start_ovms_simple_v2025.3.ps1 -Model 'OpenVINO/Mistral-7B-Instruct-v0.2-int4-cw-ov' -Target NPU" -ForegroundColor Cyan + Write-Host " # Start custom Mistral model on NPU with --task text_generation" -ForegroundColor Gray + Write-Host "" + Write-Host "DEFAULT MODELS:" -ForegroundColor Green + Write-Host " Text (GPU/CPU): OpenVINO/Phi-3.5-mini-instruct-int4-ov" -ForegroundColor White + Write-Host " Text (NPU): OpenVINO/Phi-3.5-mini-instruct-int4-cw-ov" -ForegroundColor White + Write-Host " Image (GPU): OpenVINO/FLUX.1-schnell-int4-ov" -ForegroundColor White + Write-Host " Image (CPU): OpenVINO/stable-diffusion-v1-5-int8-ov" -ForegroundColor White + Write-Host " Image (NPU): OpenVINO/FLUX.1-schnell-int8-ov" -ForegroundColor White + Write-Host "" + Write-Host "TASK AUTO-DETECTION:" -ForegroundColor Green + Write-Host " Image models (--task image_generation): *FLUX*, *diffusion*, *SDXL*, etc." -ForegroundColor White + Write-Host " Text models (--task text_generation): All other models (Phi-3, Mistral, etc.)" -ForegroundColor White + Write-Host "" + Write-Host "BUILT-IN HELP:" -ForegroundColor Green + Write-Host " Get-Help .\start_ovms_simple_v2025.3.ps1" -ForegroundColor Cyan + Write-Host " Get-Help .\start_ovms_simple_v2025.3.ps1 -Examples" -ForegroundColor Cyan + Write-Host " Get-Help .\start_ovms_simple_v2025.3.ps1 -Detailed" -ForegroundColor Cyan + Write-Host "" + Write-Host "API ACCESS:" -ForegroundColor Green + Write-Host " Once started, API available at: http://localhost:/v3" -ForegroundColor White + Write-Host "" + return +} + +# Setup OVMS if needed +$ovmsExe = Initialize-OVMS + +# Resolve model name +$sourceModel = Get-SourceModel -ModelInput $Model -TargetDevice $Target + +if (-not $sourceModel) { + Write-Error "Invalid model/target combination" + Write-Info "Available models:" + Write-Info " text - Text generation (Phi-3.5)" + Write-Info " image - Image generation (FLUX/Stable Diffusion)" + Write-Info " Or provide full OpenVINO model name" + exit 1 +} + +# Start the server +Start-OVMSServer -SourceModel $sourceModel -TargetDevice $Target -RestPort $Port diff --git a/Windows_Software_Installation/README.md b/Windows_Software_Installation/README.md new file mode 100644 index 0000000..7e1af00 --- /dev/null +++ b/Windows_Software_Installation/README.md @@ -0,0 +1,306 @@ +# Windows Software Installation for AI PC Development + +Comprehensive tools for setting up AI PC development applications and environments on Windows, including GUI-based package management and automated repository downloaders. + +## 🚀 Quick Start + +### Prerequisites +- Windows 11 with PowerShell 5.1 or PowerShell Core +- Internet connection +- Administrative privileges (required--will attempt to auto-elevate) + +### ⚠️ Important: Execution Policy Requirements +**This script must be run from an elevated PowerShell prompt.** + +If you encounter execution policy errors preventing scripts from running, use one of these methods: + +**Method 1 - Run with execution policy parameter (Recommended):** +```powershell +# For GUI mode +powershell.exe -ExecutionPolicy RemoteSigned -File ".\Setup_1.ps1" gui + +# For command line install +powershell.exe -ExecutionPolicy RemoteSigned -File ".\Setup_1.ps1" install +``` + +### Step 1: GUI Package Manager (Recommended) +**Best for setting up complete AI development environments** +```powershell +# Navigate to the installer directory +cd "Windows_Software_Installation\WingetGUI_Installer" + +# Launch the unified GUI +.\Setup_1.ps1 gui +``` + +### Step 2: Download AI Repositories and create environments +**Best for getting AI/ML code repositories** +```powershell +# Navigate to the installer directory +cd "Windows_Software_Installation\WingetGUI_Installer" + +# Run with default settings (downloads to C:\Intel) +.\Setup_2.ps1 + +# Or specify custom directory +.\Setup_2.ps1 -DevKitWorkingDir "C:\MyAIProjects" +``` + +### Option 3: Command Line Package Installation +**Best for automated/scripted environments** +```powershell +cd "Windows_Software_Installation\WingetGUI_Installer" + +# If execution policy allows scripts: +.\Setup_1.ps1 install + +# If execution policy blocks scripts: +powershell.exe -ExecutionPolicy RemoteSigned -File ".\Setup_1.ps1" install + +# Or uninstall +.\Setup_1.ps1 uninstall +``` + +--- + +## 🛠️ Available Tools + +### 🎯 Winget GUI Installer +**Modern graphical package manager for AI development tools** + +**Features:** +- ✅ **Unified Interface**: Single GUI for install/uninstall operations +- ✅ **AI Development Focus**: Curated package collections for AI/ML development +- ✅ **Progress Tracking**: Real-time installation progress with detailed logging +- ✅ **Smart Tracking**: Maintains history of installed packages for easy removal +- ✅ **Bidirectional Compatibility**: Install via GUI or command line, uninstall via either method +- ✅ **Error Handling**: Robust error reporting and retry mechanisms + +**Usage:** +```powershell +# GUI Mode (Interactive) +.\Setup_1.ps1 gui +# Or if execution policy blocks: powershell.exe -ExecutionPolicy RemoteSigned -File ".\Setup_1.ps1" gui + +# Command Line Mode (Silent) +.\Setup_1.ps1 install +# Or if execution policy blocks: powershell.exe -ExecutionPolicy RemoteSigned -File ".\Setup_1.ps1" install + +# Uninstall Mode +.\Setup_1.ps1 uninstall +``` + +### 📦 Repository Downloader +**Automated download and setup of AI/ML repositories** + +**Features:** +- ✅ **Parallel Downloads**: Downloads up to 5 repositories simultaneously +- ✅ **Retry Logic**: Automatic retry with exponential backoff (2s, 4s, 8s delays) +- ✅ **Progress Tracking**: Real-time download progress and completion status +- ✅ **Smart Skipping**: Skips existing directories and downloaded files +- ✅ **Automatic Extraction**: Extracts ZIP files and organizes into proper directories +- ✅ **Resume Capability**: Can be run multiple times safely + +**Current AI Repositories:** +1. **OpenVINO Notebooks** - Jupyter notebooks for OpenVINO toolkit +2. **OpenVINO Build & Deploy** - Build and deployment examples +3. **Ollama IPEX-LLM** - Ollama with Intel Extension for PyTorch +4. **OpenVINO GenAI** - Generative AI examples and tools +5. **WebNN Workshop** - Web Neural Network API workshop materials +6. **Open Model Zoo** - Pre-trained models collection + +--- + +## 📋 Detailed Usage Guide + +### Winget GUI Installer + +#### System Requirements +- **Windows 10/11**: Windows PowerShell 5.1 or PowerShell 7+ +- **Winget**: Windows Package Manager (installed by default on Windows 11) +- **Internet Connection**: Required for package downloads +- **Administrator Rights**: May be required for some package installations + +#### Step-by-Step Usage + +1. **Verify Winget Installation**: + ```powershell + winget --version + ``` + Should show version 1.10.X or higher + +2. **Launch GUI**: + ```powershell + cd "WingetGUI_Installer" + + # If execution policy allows scripts: + .\Setup_1.ps1 gui + + # If execution policy blocks scripts: + powershell.exe -ExecutionPolicy RemoteSigned -File ".\Setup_1.ps1" gui + ``` + +4. **Install Software**: + - Click "Install Software" + - Select desired packages from the list + - Click "Install Selected" + - Monitor real-time progress + +5. **Uninstall Software**: + - Click "Uninstall Software" + - Select packages to remove + - Confirm uninstallation + - Tracking file automatically updated + +#### Package Categories +- **Development Tools**: Git, Visual Studio Code, Visual Studio Community +- **AI/ML Frameworks**: Python, CMake, Vulkan SDK, Intel oneAPI +- **System Utilities**: Windows Terminal, PowerToys, Clink +- **Developer Productivity**: Chrome, Firefox, various IDEs + +### Repository Downloader + +#### Parameters +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------| +| `DevKitWorkingDir` | String | `C:\Intel` | Target directory for downloads | +| `MaxRetries` | Integer | `3` | Maximum retry attempts per download | + +#### Directory Structure After Download +``` +C:\Intel\ +├── openvino_notebooks\ +├── openvino_build_deploy\ +├── ollama-ipex-llm\ +├── openvino_genai\ +├── webnn_workshop\ +└── open_model_zoo\ +``` + +#### Adding New Repositories + +1. **Open `get_repos.ps1`** and locate the `$repos` array (around line 74) +2. **Add your repository**: + ```powershell + $repos = @( + # ... existing repos ... + @{ Name = "your_repo_name"; Uri = "https://github.com/owner/repo/archive/refs/heads/main.zip"; File = "repo.zip" } + ) + ``` + +3. **Common URL Patterns**: + - **Main Branch**: `https://github.com/owner/repo/archive/refs/heads/main.zip` + - **Specific Branch**: `https://github.com/owner/repo/archive/refs/heads/branch-name.zip` + - **Tagged Release**: `https://github.com/owner/repo/archive/refs/tags/v1.0.0.zip` + - **Release Asset**: `https://github.com/owner/repo/releases/download/v1.0.0/filename.zip` + +--- + +## 🔧 Advanced Configuration + +### Winget Package Configuration + +The GUI installer uses JSON configuration files for package management: + +#### Adding Winget Applications +```json +{ + "id": "Microsoft.VisualStudioCode", + "friendly_name": "Visual Studio Code", + "summary": "Code editor", + "override_flags": null, + "install_location": null, + "version": null, + "version_check": "code --version", + "dependencies": null, + "skip_install": "no" +} +``` + +#### Adding External Applications +```json +{ + "name": "custom_app", + "friendly_name": "Custom Application", + "summary": "Custom application description", + "source": "https://download.url/installer.exe", + "install_flags": "--silent --accept-eula", + "download_location": ".\\Downloads\\CustomApp", + "uninstall_command": "C:\\Path\\To\\uninstaller.exe --silent", + "dependencies": [], + "skip_install": "no" +} +``` + +### File Structure +``` +Windows_Software_Installation/ +├── README.md # This file +└── WingetGUI_Installer/ + ├── README.md # GUI installer documentation + ├── Setup_1.ps1 # Main installer script (GUI/CLI package manager) + ├── Setup_2.ps1 # Repository downloader script + ├── JSON/ + │ ├── install/ + │ │ └── applications.json # Package definitions + │ └── uninstall/ + │ └── uninstall.json # Installed package tracking + ├── logs/ # Installation logs + └── Public/ # Core functionality modules + ├── GUI.ps1 # GUI interface + ├── Install.ps1 # Installation functions + ├── Uninstall.ps1 # Uninstallation functions + ├── Append-ToJson.ps1 # JSON management + └── Write_ToLog.ps1 # Logging utilities +``` + +--- + +## 🛠️ Troubleshooting + +### Common Issues + +#### Repository Downloader +- **Download Failures**: Check internet connection and verify URLs are accessible +- **Extraction Errors**: Ensure sufficient disk space and file permissions +- **Permission Errors**: Run PowerShell as Administrator + +#### Winget GUI Installer +- **"Package not found" during uninstall**: Package was already uninstalled by another method (system will recognize this as success) +- **GUI doesn't show packages for uninstall**: No packages installed through this system yet +- **Script hangs on startup**: Check for UAC dialog waiting for user response +- **Installation shows as failed but package is installed**: Check logs for specific exit codes + +### Exit Code Reference + +#### Installation Exit Codes +- **0**: Successful installation +- **-1978335212**: Already installed (treated as success) +- **-1978335209**: Version not found (treated as failure) +- **-1978335210**: Package not found (treated as failure) + +#### Uninstall Exit Codes +- **0**: Successfully uninstalled +- **1**: Package not found (treated as success - goal achieved) +- **-1978335212**: Package not in installed list (treated as success) +- **-1978335210**: Package not found (treated as success - goal achieved) + +### Performance Notes +- **Parallel Downloads**: Up to 5 simultaneous downloads for repositories +- **Memory Usage**: ~1MB buffer per download stream +- **Retry Strategy**: Exponential backoff (2s, 4s, 8s delays) +- **Bidirectional Compatibility**: Install via any method, uninstall via any method + +--- + +## 📞 Support + +For technical assistance or feature requests: + +- **Repository Issues**: Check individual repository documentation +- **GUI Installer Issues**: Check logs in `WingetGUI_Installer\logs\` +- **Feature Requests**: Contact development team + +## 📄 License + +This script collection is provided as-is for Intel AI Dev Kit setup. Individual repositories and packages have their own licenses. diff --git a/Windows_Software_Installation/WingetGUI_Installer/JSON/install/applications.json b/Windows_Software_Installation/WingetGUI_Installer/JSON/install/applications.json new file mode 100644 index 0000000..f7a4182 --- /dev/null +++ b/Windows_Software_Installation/WingetGUI_Installer/JSON/install/applications.json @@ -0,0 +1,140 @@ +{ + "global_install_flags": "--silent --accept-package-agreements --accept-source-agreements --disable-interactivity --force", + "winget_applications": [ + { + "id": "Microsoft.NuGet", + "friendly_name": "NuGet Package Manager", + "summary": "Package manager for .NET", + "override_flags": null, + "install_location": null, + "version": null, + "version_check": null, + "dependencies": null, + "skip_install": "no" + }, + { + "id": "Microsoft.VisualStudioCode", + "friendly_name": "Visual Studio Code", + "summary": "Code editor", + "override_flags": null, + "install_location": null, + "version": null, + "version_check": null, + "dependencies": null, + "skip_install": "no" + }, + { + "id": "Microsoft.VisualStudio.2022.Community", + "friendly_name": "Visual Studio 2022 Community", + "summary": "Integrated development environment", + "override_flags": "--add Microsoft.VisualStudio.Workload.ManagedDesktop;includeRecommended --add Microsoft.VisualStudio.Workload.NativeDesktop;includeRecommended --quiet --norestart --includeRecommended --wait", + + "install_location": null, + "version": null, + "version_check": null, + "dependencies": null, + "skip_install": "no", + "note": "This package also installs VC++ redistributable, Microsoft .NET SDK" + }, + { + "id": "Python.Python.3.12", + "friendly_name": "Python 3.12", + "summary": "Python programming language interpreter", + "override_flags": null, + "install_location": null, + "version": null, + "version_check": null, + "dependencies": null, + "skip_install": "no" + }, + { + "id": "chrisant996.Clink", + "friendly_name": "Clink", + "summary": "Command line editing enhancements for cmd.exe", + "override_flags": null, + "install_location": null, + "version": null, + "version_check": null, + "dependencies": null, + "skip_install": "no" + }, + { + "id": "Google.Chrome.Canary", + "friendly_name": "Chrome Canary", + "summary": "Next-gen Chrome", + "override_flags": null, + "install_location": null, + "version": null, + "version_check": null, + "dependencies": null, + "skip_install": "no" + }, + { + "id": "Git.Git", + "friendly_name": "Git for Windows", + "summary": "Distributed version control", + "override_flags": null, + "install_location": null, + "version": null, + "version_check": null, + "dependencies": null, + "skip_install": "no" + }, + { + "id": "Kitware.CMake", + "friendly_name": "CMake", + "summary": "Cross-platform build system generator", + "override_flags": null, + "install_location": null, + "version": null, + "version_check": "cmake --version", + "dependencies": [ + { + "name": "Git", + "version": "2.49.0" + } + ], + "skip_install": "no" + }, + { + "id": "astral-sh.uv", + "friendly_name": "uv", + "summary": "Fast Python package installer and resolver", + "override_flags": null, + "install_location": null, + "version": null, + "version_check": "uv --version", + "dependencies": null, + "skip_install": "no" + }, + { + "id": "KhronosGroup.VulkanSDK", + "friendly_name": "Vulkan SDK", + "summary": "Next-generation graphics and compute API", + "override_flags": null, + "install_location": null, + "version": null, + "version_check": null, + "dependencies": null, + "skip_install": "no" + } + ], + "external_applications": [ + { + "name": "one_api_base_toolkit", + "friendly_name": "Intel oneAPI Base Toolkit", + "summary": "Intel's comprehensive suite of development tools", + "source": "https://registrationcenter-download.intel.com/akdlm/IRC_NAS/ae29263e-38b9-4d43-86c3-376d6e0668e7/intel-oneapi-base-toolkit-2025.0.1.47_offline.exe", + "install_flags": "-a --silent --eula accept", + "download_location": ".\\One_API", + "uninstall_command": "C:\\Program Files (x86)\\Intel\\oneAPI\\Installer\\installer.exe -s --action remove --product-id intel.oneapi.win.basekit.product --product-ver 2025.0.1+44", + "dependencies": [ + { + "name": "Microsoft.VisualStudio.2022.Community", + "version": "1.100.2" + } + ], + "skip_install": "yes" + } + ] +} diff --git a/Windows_Software_Installation/WingetGUI_Installer/Public/Append-ToJson.ps1 b/Windows_Software_Installation/WingetGUI_Installer/Public/Append-ToJson.ps1 new file mode 100644 index 0000000..20f8dad --- /dev/null +++ b/Windows_Software_Installation/WingetGUI_Installer/Public/Append-ToJson.ps1 @@ -0,0 +1,365 @@ +<# + Helper function to append to a JSON file + Appends an object to a specified section of a JSON file +#> +function Append-ToJson { + param ( + [Parameter(Mandatory=$true)] + [string]$jsonFilePath, + + [Parameter(Mandatory=$true)] + [ValidateSet("winget_applications", "external_applications")] + [string]$section, + + [Parameter(Mandatory=$true)] + [PSCustomObject]$newObject + ) + + # Simple retry mechanism with exponential backoff + $maxRetries = 5 + $retryCount = 0 + $success = $false + + while ($retryCount -lt $maxRetries -and -not $success) { + try { + # Check if the JSON file exists + if (-not (Test-Path -Path $jsonFilePath)) { + # Create the directory if it doesn't exist + $jsonDir = Split-Path -Parent $jsonFilePath + if (-not (Test-Path $jsonDir)) { + New-Item -Path $jsonDir -ItemType Directory -Force | Out-Null + } + + # Create a new JSON file with empty arrays + $baseJson = @{ + "winget_applications" = @() + "external_applications" = @() + } + $baseJson | ConvertTo-Json -Depth 5 | Set-Content -Path $jsonFilePath -Encoding UTF8 + } + + # Read the existing JSON with error handling + $jsonContent = $null + try { + $jsonText = Get-Content -Path $jsonFilePath -Raw -Encoding UTF8 + if ([string]::IsNullOrWhiteSpace($jsonText)) { + # Empty file, create default structure + $jsonContent = @{ + "winget_applications" = @() + "external_applications" = @() + } + } else { + $jsonContent = $jsonText | ConvertFrom-Json + } + } + catch { + Write-Warning "JSON file appears to be corrupted. Creating new file." + # Create a new JSON file with empty arrays + $jsonContent = @{ + "winget_applications" = @() + "external_applications" = @() + } + } + + # Ensure the section exists + if (-not ($jsonContent.PSObject.Properties.Name -contains $section)) { + $jsonContent | Add-Member -MemberType NoteProperty -Name $section -Value @() + } elseif ($null -eq $jsonContent.$section) { + $jsonContent.$section = @() + } + + # Use the array directly (do not wrap in @()) + $sectionArray = $jsonContent.$section + + # Check if object already exists by name or id + $exists = $false + $foundIndex = -1 + + for ($i = 0; $i -lt $sectionArray.Count; $i++) { + $item = $sectionArray[$i] + # Check for match by id first (more reliable), then by name + if (($newObject.PSObject.Properties.Name -contains "id" -and + $item.PSObject.Properties.Name -contains "id" -and + $item.id -eq $newObject.id) -or + ($item.name -eq $newObject.name)) { + $exists = $true + $foundIndex = $i + break + } + } + + # Add the object if it doesn't exist, otherwise update it + if (-not $exists) { + # Add new object to the array + $sectionArray += $newObject + $jsonContent.$section = $sectionArray + + # Log the addition for debugging + Write-Host "Added new application to ${section}: $($newObject.name)" -ForegroundColor Green + } else { + # Update existing object + if ($foundIndex -ge 0) { + # Create a combined object + $combinedObject = $sectionArray[$foundIndex].PSObject.Copy() + + # Update properties from the new object + foreach ($property in $newObject.PSObject.Properties) { + if ($combinedObject.PSObject.Properties.Name -contains $property.Name) { + $combinedObject.$($property.Name) = $property.Value + } else { + $combinedObject | Add-Member -MemberType NoteProperty -Name $property.Name -Value $property.Value + } + } + + # Update the array + $sectionArray[$foundIndex] = $combinedObject + $jsonContent.$section = $sectionArray + + # Log the update for debugging + Write-Host "Updated existing application in ${section}: $($newObject.name)" -ForegroundColor Cyan + } + } + + # Save the updated JSON with proper encoding + $jsonString = $jsonContent | ConvertTo-Json -Depth 5 + Set-Content -Path $jsonFilePath -Value $jsonString -Encoding UTF8 + + $success = $true + } + catch { + $retryCount++ + if ($retryCount -lt $maxRetries) { + # Exponential backoff: wait longer each time + $waitTime = [Math]::Min(1000, 50 * [Math]::Pow(2, $retryCount)) + Start-Sleep -Milliseconds $waitTime + } else { + throw "Failed to update JSON file after $maxRetries attempts: $_" + } + } + } +} + +# Maintain compatibility with older code that uses this function name +function AppendToJson { + param ( + [string]$json_location, + [hashtable]$data + ) + + # Validate that data has the required structure + if (-not $data.ContainsKey('winget_applications') -or -not $data.ContainsKey('external_applications')) { + throw "Data must contain winget_applications and external_applications keys" + } + + # Check if the file exists + if (Test-Path -Path $json_location) { + # Load existing data + $existing_data = Get-Content -Path $json_location -Raw | ConvertFrom-Json + + # Set merged data to existing so we can add without altering immediately + $merged_data = $existing_data + + # Initialize arrays if they don't exist + if (-not $merged_data.winget_applications) { + $merged_data.winget_applications = @() + } + if (-not $merged_data.external_applications) { + $merged_data.external_applications = @() + } + + # Append winget_applications if not already present + if ($data.ContainsKey('winget_applications')) { + foreach ($new_app in $data.winget_applications) { + # Check if application already exists (by id first, then by name) + $exists = $false + $foundIndex = -1 + $index = 0 + + foreach ($existing_app in $merged_data.winget_applications) { + # Check for match by id first (more reliable), then by name + if (($new_app.PSObject.Properties.Name -contains "id" -and + $existing_app.PSObject.Properties.Name -contains "id" -and + $existing_app.id -eq $new_app.id) -or + ($existing_app.name -eq $new_app.name)) { + $exists = $true + $foundIndex = $index + break + } + $index++ + } + + if (-not $exists) { + # Add new application + $merged_data.winget_applications += $new_app + Write-Host "Added new winget application: $($new_app.name)" -ForegroundColor Green + } else { + # Update existing application with combined properties + $combinedApp = $merged_data.winget_applications[$foundIndex].PSObject.Copy() + + # Update properties from the new object + foreach ($property in $new_app.PSObject.Properties) { + if ($combinedApp.PSObject.Properties.Name -contains $property.Name) { + # Update existing property + $combinedApp.$($property.Name) = $property.Value + } else { + # Add new property + $combinedApp | Add-Member -MemberType NoteProperty -Name $property.Name -Value $property.Value + } + } + + # Update in array + $merged_data.winget_applications[$foundIndex] = $combinedApp + Write-Host "Updated existing winget application: $($new_app.name)" -ForegroundColor Cyan + } + } + } + else { + $merged_data.winget_applications = @() + } + + # Append external_applications if not already present + if ($data.ContainsKey('external_applications')) { + foreach ($new_app in $data.external_applications) { + # Check if application already exists (by name) + $exists = $false + $foundIndex = -1 + $index = 0 + + foreach ($existing_app in $merged_data.external_applications) { + if ($existing_app.name -eq $new_app.name) { + $exists = $true + $foundIndex = $index + break + } + $index++ + } + + if (-not $exists) { + # Add new application + $merged_data.external_applications += $new_app + Write-Host "Added new external application: $($new_app.name)" -ForegroundColor Green + } else { + # Update existing application with combined properties + $combinedApp = $merged_data.external_applications[$foundIndex].PSObject.Copy() + + # Update properties from the new object + foreach ($property in $new_app.PSObject.Properties) { + if ($combinedApp.PSObject.Properties.Name -contains $property.Name) { + # Update existing property + $combinedApp.$($property.Name) = $property.Value + } else { + # Add new property + $combinedApp | Add-Member -MemberType NoteProperty -Name $property.Name -Value $property.Value + } + } + + # Update in array + $merged_data.external_applications[$foundIndex] = $combinedApp + Write-Host "Updated existing external application: $($new_app.name)" -ForegroundColor Cyan + } + } + } + else { + $merged_data.external_applications = @() + } + + # Convert merged data back to JSON and save + $json_string = $merged_data | ConvertTo-Json -Depth 5 + Set-Content -Path $json_location -Value $json_string + } + else { + # File doesn't exist, create new with data + $json_dir = Split-Path -Parent $json_location + if (-not (Test-Path $json_dir)) { + New-Item -Path $json_dir -ItemType Directory + } + New-Item -Path $json_location -ItemType File + $json_string = $data | ConvertTo-Json -Depth 5 + Set-Content -Path $json_location -Value $json_string + } +} + +<# + Helper function to remove an object from a specified section of a JSON file by id +#> +function Remove-FromJsonById { + param ( + [Parameter(Mandatory=$true)] + [string]$jsonFilePath, + [Parameter(Mandatory=$true)] + [ValidateSet("winget_applications", "external_applications")] + [string]$section, + [Parameter(Mandatory=$true)] + [string]$id + ) + + Write-Host "Remove-FromJsonById called with: $jsonFilePath, $section, $id" -ForegroundColor Magenta + + if (-not (Test-Path -Path $jsonFilePath)) { + Write-Warning "JSON file does not exist: $jsonFilePath" + return + } + + $jsonText = Get-Content -Path $jsonFilePath -Raw -Encoding UTF8 + if ([string]::IsNullOrWhiteSpace($jsonText)) { + Write-Warning "JSON file is empty: $jsonFilePath" + return + } + + $jsonContent = $jsonText | ConvertFrom-Json + + if (-not ($jsonContent.PSObject.Properties.Name -contains $section)) { + Write-Warning "Section '$section' does not exist in JSON." + return + } + + # Always treat as array, even if only one object + $sectionArray = @() + if ($jsonContent.$section -is [System.Collections.IEnumerable] -and + -not ($jsonContent.$section -is [string])) { + $sectionArray = @($jsonContent.$section) + } elseif ($null -ne $jsonContent.$section) { + $sectionArray = @($jsonContent.$section) + } + + # Flatten in case it's an array of arrays (PowerShell quirk) + $flatArray = @() + foreach ($item in $sectionArray) { + if ($item -is [System.Collections.IEnumerable] -and -not ($item -is [string])) { + $flatArray += $item + } else { + $flatArray += ,$item + } + } + + # Remove the entry by id (case-insensitive, trimmed) + $filteredArray = @() + foreach ($item in $flatArray) { + $itemId = "" + if ($item.PSObject.Properties.Name -contains "id") { + $itemId = ($item.id | Out-String).Trim() + } + if ($itemId -ieq $id.Trim()) { + Write-Host "Match found: Removing item.id '$itemId' (target id: '$($id.Trim())')" -ForegroundColor DarkYellow + # Do not add to filteredArray, i.e., remove it + } else { + $filteredArray += $item + } + } + + $jsonContent.$section = $filteredArray + + # If both arrays are empty, delete the file + $wingetEmpty = -not $jsonContent.winget_applications -or $jsonContent.winget_applications.Count -eq 0 + $externalEmpty = -not $jsonContent.external_applications -or $jsonContent.external_applications.Count -eq 0 + + if ($wingetEmpty -and $externalEmpty) { + Remove-Item -Path $jsonFilePath -Force + Write-Host "All applications removed. Deleted $jsonFilePath." -ForegroundColor Red + } else { + # Save the updated JSON + $jsonString = $jsonContent | ConvertTo-Json -Depth 5 + Set-Content -Path $jsonFilePath -Value $jsonString -Encoding UTF8 + Write-Host "Removed application from $section by id: $id" -ForegroundColor Yellow + } +} diff --git a/Windows_Software_Installation/WingetGUI_Installer/Public/GUI.ps1 b/Windows_Software_Installation/WingetGUI_Installer/Public/GUI.ps1 new file mode 100644 index 0000000..64573ea --- /dev/null +++ b/Windows_Software_Installation/WingetGUI_Installer/Public/GUI.ps1 @@ -0,0 +1,605 @@ +<# +.SYNOPSIS + GUI module for the Environment Setup Tool. + +.DESCRIPTION + This module provides GUI functions for the Environment Setup Tool, + including package selection, installation, and uninstallation interfaces. + +.NOTES + This is part of the Environment Setup tool for developers. + Authors: + - Vijay (vijay.chandrashekar@intel.com) + - Ram (vaithi.s.ramadoss@intel.com) + - Ben (benjamin.j.odom@intel.com) +#> + +# Load required .NET assemblies +Add-Type -AssemblyName System.Windows.Forms +Add-Type -AssemblyName System.Drawing + +<# + Displays the main GUI for the Environment Setup Tool. +#> +function Show-MainGUI { + [CmdletBinding()] + param( + [Parameter(Mandatory)] + $applications, + [string]$install_log_file, + [string]$json_uninstall_file_path + ) + + # Create the main form + $mainForm = New-Object System.Windows.Forms.Form + $mainForm.Text = 'Environment Setup - Main Menu' + $mainForm.Size = New-Object System.Drawing.Size(500, 300) + $mainForm.StartPosition = 'CenterScreen' + $mainForm.FormBorderStyle = 'FixedDialog' + $mainForm.MaximizeBox = $false + + # Title label + $lblTitle = New-Object System.Windows.Forms.Label + $lblTitle.Text = 'Environment Setup Tool' + $lblTitle.Font = New-Object System.Drawing.Font('Arial', 16, [System.Drawing.FontStyle]::Bold) + $lblTitle.Size = New-Object System.Drawing.Size(400, 30) + $lblTitle.Location = New-Object System.Drawing.Point(50, 30) + $lblTitle.TextAlign = 'MiddleCenter' + + # Description label + $lblDesc = New-Object System.Windows.Forms.Label + $lblDesc.Text = 'Choose an action to perform:' + $lblDesc.Size = New-Object System.Drawing.Size(400, 20) + $lblDesc.Location = New-Object System.Drawing.Point(50, 80) + $lblDesc.TextAlign = 'MiddleCenter' + + # Install button + $btnInstall = New-Object System.Windows.Forms.Button + $btnInstall.Text = 'Install Software' + $btnInstall.Size = New-Object System.Drawing.Size(150, 40) + $btnInstall.Location = New-Object System.Drawing.Point(80, 120) + $btnInstall.Font = New-Object System.Drawing.Font('Arial', 10) + + # Uninstall button + $btnUninstall = New-Object System.Windows.Forms.Button + $btnUninstall.Text = 'Uninstall Software' + $btnUninstall.Size = New-Object System.Drawing.Size(150, 40) + $btnUninstall.Location = New-Object System.Drawing.Point(270, 120) + $btnUninstall.Font = New-Object System.Drawing.Font('Arial', 10) + + # Exit button + $btnExit = New-Object System.Windows.Forms.Button + $btnExit.Text = 'Exit' + $btnExit.Size = New-Object System.Drawing.Size(100, 30) + $btnExit.Location = New-Object System.Drawing.Point(200, 200) + + # Add controls to form + $mainForm.Controls.AddRange(@($lblTitle, $lblDesc, $btnInstall, $btnUninstall, $btnExit)) + + # Button event handlers + $btnInstall.Add_Click({ + $mainForm.Hide() + $selectedPackages = Show-PackageSelectionGUI -applications $applications -install_log_file $install_log_file + + if ($selectedPackages) { + Write-Host "Installing selected packages..." -ForegroundColor Green + + # Create uninstall_json_file if it doesn't exist + if (-not [string]::IsNullOrWhiteSpace($json_uninstall_file_path)) { + $uninstallDir = Split-Path -Path $json_uninstall_file_path -Parent + if (-not (Test-Path -Path $uninstallDir)) { + New-Item -Path $uninstallDir -ItemType Directory -Force | Out-Null + } + + if (-not (Test-Path -Path $json_uninstall_file_path)) { + $json_structure = @{ + "winget_applications" = @() + "external_applications" = @() + } + $json_structure | ConvertTo-Json | Set-Content -Path $json_uninstall_file_path + } + } + + $installResults = Install-SelectedPackages -selectedPackages $selectedPackages -log_file $install_log_file -uninstall_json_file $json_uninstall_file_path + + # Copy install logs to desktop + $username = [Environment]::UserName + Copy-Item -Path $install_log_file -Destination "C:\Users\$username\Desktop\install_logs.txt" + + Show-InstallResults -installResults $installResults + } + $mainForm.Close() + }) + + $btnUninstall.Add_Click({ + $mainForm.Hide() + $selectedPackages = Show-UninstallGUI -json_uninstall_file_path $json_uninstall_file_path + + if ($selectedPackages) { + Write-Host "Uninstalling selected packages..." -ForegroundColor Yellow + $uninstallResults = Uninstall-SelectedPackages -selectedPackages $selectedPackages -log_file $install_log_file -json_uninstall_file_path $json_uninstall_file_path + Show-UninstallResults -uninstallResults $uninstallResults + } + $mainForm.Close() + }) + + $btnExit.Add_Click({ $mainForm.Close() }) + + # Show the form + [void] $mainForm.ShowDialog() +} + +<# + Displays the installation results summary. +#> +function Show-InstallResults { + [CmdletBinding()] + param($installResults) + + # Create detailed result message + $resultMessage = "Installation Summary:`n" + $resultMessage += "Total packages: $($installResults.TotalPackages)`n" + $resultMessage += "Successfully installed: $($installResults.SuccessfulInstalls)`n" + $resultMessage += "Failed installations: $($installResults.FailedInstalls)`n" + + if ($installResults.FailedInstalls -gt 0) { + $resultMessage += "`nFailed packages:`n" + foreach ($failedPkg in $installResults.FailedPackages) { + $resultMessage += "- $failedPkg`n" + } + } + + $resultMessage += "`nCheck the install logs on your desktop for details." + + # Choose appropriate icon and title based on results + if ($installResults.FailedInstalls -eq 0) { + $icon = [System.Windows.Forms.MessageBoxIcon]::Information + $title = 'Environment Setup - Installation Completed Successfully' + } elseif ($installResults.SuccessfulInstalls -eq 0) { + $icon = [System.Windows.Forms.MessageBoxIcon]::Error + $title = 'Environment Setup - Installation Failed' + } else { + $icon = [System.Windows.Forms.MessageBoxIcon]::Warning + $title = 'Environment Setup - Installation Completed with Errors' + } + + [System.Windows.Forms.MessageBox]::Show( + $resultMessage, + $title, + [System.Windows.Forms.MessageBoxButtons]::OK, + $icon + ) +} + +<# + Displays a GUI for selecting packages to install. +#> +function Show-PackageSelectionGUI { + [CmdletBinding()] + param( + [Parameter(Mandatory)] + $applications, + [string]$install_log_file + ) + + # Build a DataTable for the DataGridView + $dt = New-Object System.Data.DataTable + $dt.Columns.Add('Check', [bool]) | Out-Null + $dt.Columns.Add('Id', [string]) | Out-Null + $dt.Columns.Add('FriendlyName', [string]) | Out-Null + $dt.Columns.Add('Summary', [string]) | Out-Null + $dt.Columns.Add('Version', [string]) | Out-Null + $dt.Columns.Add('Type', [string]) | Out-Null + + # Add winget applications + foreach ($app in $applications.winget_applications) { + if ($null -eq $app) { continue } + + $row = $dt.NewRow() + # Check if skip_install is defined and not set to "yes" + $row.Check = if ($null -ne $app.skip_install) { $app.skip_install -ne "yes" } else { $true } + $row.Id = if ($null -ne $app.id -and $app.id -ne '') { $app.id } else { $app.name } + $row.FriendlyName = if ($null -ne $app.friendly_name -and $app.friendly_name -ne '') { $app.friendly_name } else { $app.name } + $row.Summary = if ($null -ne $app.summary -and $app.summary -ne '') { $app.summary } else { "No description available" } + $row.Version = if ($null -ne $app.version -and $app.version -ne '') { $app.version } else { "Latest" } + $row.Type = "Winget" + $dt.Rows.Add($row) + } + + # Add external applications + foreach ($app in $applications.external_applications) { + if ($null -eq $app) { continue } + + $row = $dt.NewRow() + # Check if skip_install is defined and not set to "yes" + $row.Check = if ($null -ne $app.skip_install) { $app.skip_install -ne "yes" } else { $true } + $row.Id = $app.name + $row.FriendlyName = if ($null -ne $app.friendly_name -and $app.friendly_name -ne '') { $app.friendly_name } else { $app.name } + $row.Summary = if ($null -ne $app.summary -and $app.summary -ne '') { $app.summary } else { "External application" } + $row.Version = "External" + $row.Type = "External" + $dt.Rows.Add($row) + } + + # Create the form + $frm = New-Object System.Windows.Forms.Form + $frm.Text = 'Environment Setup - Select Software to Install' + $frm.Size = New-Object System.Drawing.Size(1000, 600) + $frm.StartPosition = 'CenterScreen' + $frm.FormBorderStyle = 'Sizable' + + # DataGridView + $dg = New-Object System.Windows.Forms.DataGridView + $dg.AutoGenerateColumns = $true + $dg.DataSource = $dt + $dg.Dock = 'Fill' + $dg.AutoSizeColumnsMode = 'AllCells' + $dg.AllowUserToAddRows = $false + $dg.AllowUserToDeleteRows = $false + $dg.SelectionMode = 'FullRowSelect' + + # Configure columns + $dg.Refresh() + if ($dg.Columns.Count -gt 0) { + $dg.Columns[0].HeaderText = 'Install?' + $dg.Columns[0].Width = 70 + + if ($dg.Columns.Count -gt 1) { + $dg.Columns[1].HeaderText = 'Package ID' + $dg.Columns[1].ReadOnly = $true + $dg.Columns[1].Width = 200 + } + if ($dg.Columns.Count -gt 2) { + $dg.Columns[2].HeaderText = 'Name' + $dg.Columns[2].ReadOnly = $true + $dg.Columns[2].Width = 200 + } + if ($dg.Columns.Count -gt 3) { + $dg.Columns[3].HeaderText = 'Description' + $dg.Columns[3].ReadOnly = $true + $dg.Columns[3].Width = 300 + } + if ($dg.Columns.Count -gt 4) { + $dg.Columns[4].HeaderText = 'Version' + $dg.Columns[4].ReadOnly = $true + $dg.Columns[4].Width = 100 + } + if ($dg.Columns.Count -gt 5) { + $dg.Columns[5].HeaderText = 'Type' + $dg.Columns[5].ReadOnly = $true + $dg.Columns[5].Width = 80 + } + } + + # Bottom panel with buttons + $pan = New-Object System.Windows.Forms.Panel + $pan.Dock = 'Bottom' + $pan.Height = 50 + + $btnSelectAll = New-Object System.Windows.Forms.Button + $btnSelectAll.Text = 'Select All' + $btnSelectAll.Width = 80 + $btnSelectAll.Location = New-Object System.Drawing.Point(10, 10) + + $btnClearAll = New-Object System.Windows.Forms.Button + $btnClearAll.Text = 'Clear All' + $btnClearAll.Width = 80 + $btnClearAll.Location = New-Object System.Drawing.Point(100, 10) + + $btnInstall = New-Object System.Windows.Forms.Button + $btnInstall.Text = 'Install Selected' + $btnInstall.Width = 120 + $btnInstall.Location = New-Object System.Drawing.Point(190, 10) + + $btnCancel = New-Object System.Windows.Forms.Button + $btnCancel.Text = 'Close' + $btnCancel.Width = 80 + $btnCancel.Location = New-Object System.Drawing.Point(320, 10) + + $pan.Controls.AddRange(@($btnSelectAll, $btnClearAll, $btnInstall, $btnCancel)) + $frm.Controls.AddRange(@($dg, $pan)) + + # Button event handlers + $btnSelectAll.Add_Click({ + foreach ($row in $dt.Rows) { + $row.Check = $true + } + }) + + $btnClearAll.Add_Click({ + foreach ($row in $dt.Rows) { + $row.Check = $false + } + }) + + $btnInstall.Add_Click({ + $selectedRows = $dt | Where-Object { $_.Check } + + if (-not $selectedRows) { + [System.Windows.Forms.MessageBox]::Show( + 'No packages selected.', + 'Environment Setup', + [System.Windows.Forms.MessageBoxButtons]::OK, + [System.Windows.Forms.MessageBoxIcon]::Information + ) + return + } + + $cnt = @($selectedRows).Count + $pkgWord = if ($cnt -eq 1) { 'package' } else { 'packages' } + $confirm = [System.Windows.Forms.MessageBox]::Show( + "You are about to install $cnt $pkgWord. Continue?", + 'Environment Setup - Confirm Installation', + [System.Windows.Forms.MessageBoxButtons]::YesNo, + [System.Windows.Forms.MessageBoxIcon]::Question + ) + + if ($confirm -ne 'Yes') { return } + + # Close the form and return selected packages + $script:selectedPackages = $selectedRows + $frm.DialogResult = [System.Windows.Forms.DialogResult]::OK + $frm.Close() + }) + + $btnCancel.Add_Click({ $frm.Close() }) + + # Show the form + $result = $frm.ShowDialog() + + if ($result -eq [System.Windows.Forms.DialogResult]::OK) { + return $script:selectedPackages + } + + return $null +} + +<# + Displays a GUI for selecting packages to uninstall. +#> +function Show-UninstallGUI { + [CmdletBinding()] + param( + [string]$json_uninstall_file_path + ) + + # Check if uninstall.json exists + if (-not (Test-Path -Path $json_uninstall_file_path)) { + [System.Windows.Forms.MessageBox]::Show( + "No uninstall.json file found. No applications have been tracked for uninstallation.", + 'Environment Setup - No Applications to Uninstall', + [System.Windows.Forms.MessageBoxButtons]::OK, + [System.Windows.Forms.MessageBoxIcon]::Information + ) + return $null + } + + # Load uninstall data + $uninstallData = Get-Content -Path $json_uninstall_file_path -Raw | ConvertFrom-Json + + # Check if there are any applications to uninstall + $totalApps = 0 + if ($uninstallData.winget_applications -and $uninstallData.winget_applications.Count) { + $totalApps += $uninstallData.winget_applications.Count + } + if ($uninstallData.external_applications -and $uninstallData.external_applications.Count) { + $totalApps += $uninstallData.external_applications.Count + } + + if ($totalApps -eq 0) { + [System.Windows.Forms.MessageBox]::Show( + "No applications are currently tracked for uninstallation.", + 'Environment Setup - No Applications to Uninstall', + [System.Windows.Forms.MessageBoxButtons]::OK, + [System.Windows.Forms.MessageBoxIcon]::Information + ) + return $null + } + + # Build a DataTable for the DataGridView + $dt = New-Object System.Data.DataTable + $dt.Columns.Add('Check', [bool]) | Out-Null + $dt.Columns.Add('Id', [string]) | Out-Null + $dt.Columns.Add('FriendlyName', [string]) | Out-Null + $dt.Columns.Add('Version', [string]) | Out-Null + $dt.Columns.Add('Type', [string]) | Out-Null + + # Add winget applications from uninstall.json + if ($uninstallData.winget_applications -and $uninstallData.winget_applications.Count -gt 0) { + foreach ($app in $uninstallData.winget_applications) { + $row = $dt.NewRow() + $row.Check = $false + # For winget apps, use 'id' field (e.g., "Microsoft.VisualStudioCode") + $row.Id = if ($app.id) { $app.id } else { $app.name } + # Use friendly_name if available, otherwise fall back to id or name + $row.FriendlyName = if ($app.friendly_name) { $app.friendly_name } elseif ($app.id) { $app.id } else { $app.name } + $row.Version = if ($app.version) { $app.version } else { "Latest" } + $row.Type = "Winget" + $dt.Rows.Add($row) + } + } + + # Add external applications from uninstall.json + if ($uninstallData.external_applications -and $uninstallData.external_applications.Count -gt 0) { + foreach ($app in $uninstallData.external_applications) { + $row = $dt.NewRow() + $row.Check = $false + # For external apps, use 'name' field + $row.Id = $app.name + # Use friendly_name if available, otherwise fall back to name + $row.FriendlyName = if ($app.friendly_name) { $app.friendly_name } else { $app.name } + $row.Version = "External" + $row.Type = "External" + $dt.Rows.Add($row) + } + } + + # Create the form + $frm = New-Object System.Windows.Forms.Form + $frm.Text = 'Environment Setup - Select Software to Uninstall' + $frm.Size = New-Object System.Drawing.Size(900, 500) + $frm.StartPosition = 'CenterScreen' + $frm.FormBorderStyle = 'Sizable' + + # DataGridView + $dg = New-Object System.Windows.Forms.DataGridView + $dg.AutoGenerateColumns = $true + $dg.DataSource = $dt + $dg.Dock = 'Fill' + $dg.AutoSizeColumnsMode = 'AllCells' + $dg.AllowUserToAddRows = $false + $dg.AllowUserToDeleteRows = $false + $dg.SelectionMode = 'FullRowSelect' + + # Configure columns + $dg.Refresh() + if ($dg.Columns.Count -gt 0) { + $dg.Columns[0].HeaderText = 'Uninstall?' + $dg.Columns[0].Width = 70 + + if ($dg.Columns.Count -gt 1) { + $dg.Columns[1].HeaderText = 'Package ID' + $dg.Columns[1].ReadOnly = $true + $dg.Columns[1].Width = 200 + } + if ($dg.Columns.Count -gt 2) { + $dg.Columns[2].HeaderText = 'Name' + $dg.Columns[2].ReadOnly = $true + $dg.Columns[2].Width = 200 + } + if ($dg.Columns.Count -gt 3) { + $dg.Columns[3].HeaderText = 'Version' + $dg.Columns[3].ReadOnly = $true + $dg.Columns[3].Width = 100 + } + if ($dg.Columns.Count -gt 4) { + $dg.Columns[4].HeaderText = 'Type' + $dg.Columns[4].ReadOnly = $true + $dg.Columns[4].Width = 80 + } + } + + # Bottom panel with buttons + $pan = New-Object System.Windows.Forms.Panel + $pan.Dock = 'Bottom' + $pan.Height = 50 + + $btnSelectAll = New-Object System.Windows.Forms.Button + $btnSelectAll.Text = 'Select All' + $btnSelectAll.Width = 80 + $btnSelectAll.Location = New-Object System.Drawing.Point(10, 10) + + $btnClearAll = New-Object System.Windows.Forms.Button + $btnClearAll.Text = 'Clear All' + $btnClearAll.Width = 80 + $btnClearAll.Location = New-Object System.Drawing.Point(100, 10) + + $btnUninstall = New-Object System.Windows.Forms.Button + $btnUninstall.Text = 'Uninstall Selected' + $btnUninstall.Width = 120 + $btnUninstall.Location = New-Object System.Drawing.Point(190, 10) + + $btnCancel = New-Object System.Windows.Forms.Button + $btnCancel.Text = 'Cancel' + $btnCancel.Width = 80 + $btnCancel.Location = New-Object System.Drawing.Point(320, 10) + + $pan.Controls.AddRange(@($btnSelectAll, $btnClearAll, $btnUninstall, $btnCancel)) + $frm.Controls.AddRange(@($dg, $pan)) + + # Button event handlers + $btnSelectAll.Add_Click({ + foreach ($row in $dt.Rows) { + $row.Check = $true + } + }) + + $btnClearAll.Add_Click({ + foreach ($row in $dt.Rows) { + $row.Check = $false + } + }) + + $btnUninstall.Add_Click({ + $selectedRows = $dt | Where-Object { $_.Check } + + if (-not $selectedRows) { + [System.Windows.Forms.MessageBox]::Show( + 'No packages selected.', + 'Environment Setup', + [System.Windows.Forms.MessageBoxButtons]::OK, + [System.Windows.Forms.MessageBoxIcon]::Information + ) + return + } + + $cnt = $selectedRows.Count + $confirm = [System.Windows.Forms.MessageBox]::Show( + "You are about to uninstall $cnt package(s). This action cannot be undone. Continue?", + 'Environment Setup - Confirm Uninstallation', + [System.Windows.Forms.MessageBoxButtons]::YesNo, + [System.Windows.Forms.MessageBoxIcon]::Warning + ) + + if ($confirm -ne 'Yes') { return } + + # Close the form and return selected packages + $script:selectedUninstallPackages = $selectedRows + $frm.DialogResult = [System.Windows.Forms.DialogResult]::OK + $frm.Close() + }) + + $btnCancel.Add_Click({ $frm.Close() }) + + # Show the form + $result = $frm.ShowDialog() + + if ($result -eq [System.Windows.Forms.DialogResult]::OK) { + return $script:selectedUninstallPackages + } + + return $null +} + +<# + Displays a summary of uninstallation results. +#> +function Show-UninstallResults { + [CmdletBinding()] + param($uninstallResults) + + # Create detailed result message + $resultMessage = "Uninstallation Summary:`n" + $resultMessage += "Total packages: $($uninstallResults.TotalPackages)`n" + $resultMessage += "Successfully uninstalled: $($uninstallResults.SuccessfulUninstalls)`n" + $resultMessage += "Failed uninstallations: $($uninstallResults.FailedUninstalls)`n" + + if ($uninstallResults.FailedUninstalls -gt 0) { + $resultMessage += "`nFailed packages:`n" + foreach ($failedPkg in $uninstallResults.FailedPackages) { + $resultMessage += "- $failedPkg`n" + } + } + + # Choose appropriate icon and title based on results + if ($uninstallResults.FailedUninstalls -eq 0) { + $icon = [System.Windows.Forms.MessageBoxIcon]::Information + $title = 'Environment Setup - Uninstallation Completed Successfully' + } elseif ($uninstallResults.SuccessfulUninstalls -eq 0) { + $icon = [System.Windows.Forms.MessageBoxIcon]::Error + $title = 'Environment Setup - Uninstallation Failed' + } else { + $icon = [System.Windows.Forms.MessageBoxIcon]::Warning + $title = 'Environment Setup - Uninstallation Completed with Errors' + } + + [System.Windows.Forms.MessageBox]::Show( + $resultMessage, + $title, + [System.Windows.Forms.MessageBoxButtons]::OK, + $icon + ) +} + +# Functions are automatically available when the script is sourced +# No need to export members since this is not a module diff --git a/Windows_Software_Installation/WingetGUI_Installer/Public/Install.ps1 b/Windows_Software_Installation/WingetGUI_Installer/Public/Install.ps1 new file mode 100644 index 0000000..ce98115 --- /dev/null +++ b/Windows_Software_Installation/WingetGUI_Installer/Public/Install.ps1 @@ -0,0 +1,314 @@ +# Install a list of selected packages (winget and external) +function Install-SelectedPackages { + param ( + [Parameter(Mandatory=$true)] + [array]$selectedPackages, + [Parameter(Mandatory=$true)] + [string]$log_file, + [Parameter(Mandatory=$true)] + [string]$uninstall_json_file + ) + + # Ensure execution policy allows script execution + try { + $currentPolicy = Get-ExecutionPolicy -Scope CurrentUser + if ($currentPolicy -eq "Restricted" -or $currentPolicy -eq "AllSigned") { + Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser -Force + Write-Host "Updated execution policy from $currentPolicy to RemoteSigned for CurrentUser" -ForegroundColor Yellow + Write-ToLog -message "Updated execution policy from $currentPolicy to RemoteSigned for CurrentUser" -log_file $log_file + } + } + catch { + Write-Host "Warning: Could not set execution policy: $_" -ForegroundColor Yellow + Write-ToLog -message "Warning: Could not set execution policy: $_" -log_file $log_file + } + + $results = @() + $installedCount = 0 + $failedCount = 0 + $skippedCount = 0 + $failedPackages = @() + # Reload the original JSON so we can merge in all properties (like override_flags) + $jsonPath = Join-Path (Split-Path $PSScriptRoot -Parent) 'JSON/install/applications.json' + $allAppsJson = Get-Content -Path $jsonPath -Raw | ConvertFrom-Json + $allWingetApps = $allAppsJson.winget_applications + + foreach ($app in $selectedPackages) { + # Try to find the full app object from the original JSON by id + $fullApp = $null + if ($app.PSObject.Properties["id"]) { + $fullApp = $allWingetApps | Where-Object { $_.id -eq $app.id } + } elseif ($app.PSObject.Properties["name"]) { + $fullApp = $allWingetApps | Where-Object { $_.id -eq $app.name } + } + if ($fullApp) { + # Merge missing properties from fullApp into $app + foreach ($prop in $fullApp.PSObject.Properties) { + if (-not $app.PSObject.Properties[$prop.Name]) { + $app | Add-Member -NotePropertyName $prop.Name -NotePropertyValue $prop.Value + } + } + } + $appType = if ($app.PSObject.Properties["id"]) { "winget" } elseif ($app.PSObject.Properties["source"]) { "external" } else { "unknown" } + $appName = if ($app.friendly_name) { $app.friendly_name } elseif ($app.name) { $app.name } elseif ($app.id) { $app.id } else { "UnknownApp" } + $overrideFlags = $null + if ($app.PSObject.Properties["override_flags"]) { + $overrideFlags = $app.override_flags + if ($null -ne $app.override_flags) { + } else { + } + } elseif ($app.PSObject.Properties["OverrideFlags"]) { + $overrideFlags = $app.OverrideFlags + if ($null -ne $app.OverrideFlags) { + } else { + } + } else { + } + $result = @{ name = $appName; type = $appType; status = "skipped"; message = "" } + + if ($appType -eq "winget") { + try { + Write-ToLog -message "Installing winget app: $appName" -log_file $log_file + $wingetArgs = @("install", "--id", $app.id, "--accept-source-agreements", "--accept-package-agreements", "-h") + if ($overrideFlags) { + Write-ToLog -message ("override_flags/OverrideFlags for " + $appName + ": " + $overrideFlags) -log_file $log_file + $wingetArgs += "--override" + $wingetArgs += "`"$overrideFlags`"" + } elseif ($app.install_args) { + $wingetArgs += $app.install_args + } + $wingetArgsString = $wingetArgs -join ' ' + $process = Start-Process -FilePath "winget" -ArgumentList $wingetArgs -PassThru -Wait -NoNewWindow + $exit_code = $process.ExitCode + $success = Test-InstallationSuccess -exit_code $exit_code -app_name $appName -log_file $log_file + if ($success) { + $installedCount++ + # Always add to uninstall tracking immediately, with required fields + $trackingApp = [PSCustomObject]@{ + id = if ($app.id) { $app.id } elseif ($app.name) { $app.name } else { $appName } + name = if ($app.name) { $app.name } elseif ($app.id) { $app.id } else { $appName } + friendly_name = if ($app.friendly_name) { $app.friendly_name } else { $appName } + version = if ($app.version) { $app.version } else { "Latest" } + installed_on = (Get-Date -Format "yyyy-MM-dd HH:mm:ss") + last_updated = (Get-Date -Format "yyyy-MM-dd HH:mm:ss") + } + Append-ToJson -jsonFilePath $uninstall_json_file -section "winget_applications" -newObject $trackingApp + $result.status = "success" + $result.message = "Installed and tracked." + } else { + $failedCount++ + $failedPackages += $appName + $result.status = "failed" + $result.message = "Install failed." + } + } catch { + $failedCount++ + $failedPackages += $appName + Write-ToLog -message ("Exception during winget install for ${appName}: " + ($_ | Out-String)) -log_file $log_file + $result.status = "error" + $result.message = $_.Exception.Message + } + } elseif ($appType -eq "external") { + # Always ensure uninstall tracking is updated for external apps as well, with required fields + $success = Install-ExternalApplication -app $app -log_file $log_file -uninstall_json_file $uninstall_json_file + if ($success) { + $installedCount++ + $result.status = "success" + $result.message = "Installed and tracked." + } else { + $failedCount++ + $failedPackages += $appName + $result.status = "failed" + $result.message = "Install failed." + } + } else { + $skippedCount++ + $result.status = "skipped" + $result.message = "Unknown app type." + } + $results += $result + } + $summary = @{ + TotalPackages = $selectedPackages.Count + SuccessfulInstalls = $installedCount + FailedInstalls = $failedCount + SkippedInstalls = $skippedCount + FailedPackages = if ($failedPackages -and $failedPackages.Count -gt 0) { $failedPackages -join ", " } else { "None" } + } + Write-Host "Install Summary: Total: $($summary.TotalPackages), Installed: $($summary.SuccessfulInstalls), Failed: $($summary.FailedInstalls), Skipped: $($summary.SkippedInstalls), FailedPackages: $($summary.FailedPackages)" -ForegroundColor Green + Write-ToLog -message "Install Summary: Total: $($summary.TotalPackages), Installed: $($summary.SuccessfulInstalls), Failed: $($summary.FailedInstalls), Skipped: $($summary.SkippedInstalls), FailedPackages: $($summary.FailedPackages)" -log_file $log_file + return $summary +} +# Install.ps1 +# Module containing all installation-related functions + +# Test if a winget installation was successful +function Test-InstallationSuccess { + param ( + [int]$exit_code, + [string]$app_name, + [string]$log_file + ) + switch ($exit_code) { + 0 { + Write-ToLog -message "Successfully installed $app_name" -log_file $log_file + return $true + } + -1978335189 { + Write-ToLog -message "Application $app_name is already installed" -log_file $log_file + return $true + } + -1978335188 { + Write-ToLog -message "No applicable installer found for $app_name" -log_file $log_file + return $false + } + -1978335186 { + Write-ToLog -message "Installation of $app_name was blocked by policy" -log_file $log_file + return $false + } + # Add any other exit codes that winget might return + -1978335210 { + Write-ToLog -message "Package $app_name not found in the source" -log_file $log_file + return $false + } + -1978335212 { + Write-ToLog -message "Package $app_name is already installed (alternative code)" -log_file $log_file + return $true + } + -1978335181 { + Write-ToLog -message "Application $app_name completed successfully but a reboot is required" -log_file $log_file + return $true + } + -1978335182 { + Write-ToLog -message "Application $app_name installation completed with restart required" -log_file $log_file + return $true + } + 87 { + # Error code for "The parameter is incorrect" - common with some installations + Write-ToLog -message "Application $app_name completed with exit code 87 (parameter incorrect) - likely already installed" -log_file $log_file + return $true + } + 3010 { + # Common installer exit code for reboot required + Write-ToLog -message "Application $app_name successfully installed (reboot required)" -log_file $log_file + return $true + } + 1 { + # Some installers use 1 to indicate success with warnings or already installed + Write-ToLog -message "Application $app_name completed with exit code 1 (success with warnings or already installed)" -log_file $log_file + return $true + } + default { + Write-ToLog -message "Failed to install $app_name. Exit code: $exit_code" -log_file $log_file + return $false + } + } +} + +# Install an external application +function Install-ExternalApplication { + param ( + [PSCustomObject]$app, + [string]$log_file, + [string]$uninstall_json_file + ) + + # Get display name for logging + $appDisplayName = if ($app.friendly_name) { $app.friendly_name } else { $app.name } + + Write-ToLog -message "Installing external application $appDisplayName" -log_file $log_file + + # Check for required properties + if (-not $app.name -or -not $app.source) { + Write-ToLog -message "Error: External application $appDisplayName is missing required properties (name or source)" -log_file $log_file + return $false + } + + # Create a temporary directory for downloads if it doesn't exist + $temp_dir = Join-Path $env:TEMP "EnvSetup_Downloads" + if (-not (Test-Path $temp_dir)) { + New-Item -ItemType Directory -Path $temp_dir -Force | Out-Null + } + + try { + # Download the installer + $installer_path = Join-Path $temp_dir "$($app.name)_installer$(Split-Path $app.source -Extension)" + try { + Write-ToLog -message "Downloading $($appDisplayName) from $($app.source)" -log_file $log_file + Invoke-WebRequest -Uri $app.source -OutFile $installer_path -UseBasicParsing + Write-ToLog -message "Downloaded installer for $($appDisplayName) to $installer_path" -log_file $log_file + } + catch { + Write-ToLog -message "Failed to download installer for $($appDisplayName): $_" -log_file $log_file + return $false + } + + # Run the installer + $arguments = @() + if ($app.install_flags) { + $arguments = $app.install_flags -split '\s+' + } elseif ($app.install_args) { + # For backward compatibility + $arguments = $app.install_args -split '\s+' + } + + Write-ToLog -message "Running installer for $appDisplayName with arguments: $($arguments -join ' ')" -log_file $log_file + $process = Start-Process -FilePath $installer_path -ArgumentList $arguments -PassThru -Wait -NoNewWindow + $exit_code = $process.ExitCode + + $success = ($exit_code -eq 0) + Write-ToLog -message "Installation of $($appDisplayName) completed with exit code $exit_code" -log_file $log_file + + # Always add to tracking if install succeeded or app is already installed (1603) + if ($success -or $exit_code -eq 1603) { + # Add installation timestamp and additional info to tracking + $trackingApp = [PSCustomObject]@{ + name = if ($app.name) { $app.name } else { $appDisplayName } + friendly_name = if ($app.friendly_name) { $app.friendly_name } else { $appDisplayName } + version = if ($app.version) { $app.version } else { "Latest" } + uninstall_command = if ($app.PSObject.Properties.Name -contains "uninstall_command" -and $app.uninstall_command) { $app.uninstall_command } else { "" } + installed_on = (Get-Date -Format "yyyy-MM-dd HH:mm:ss") + last_updated = (Get-Date -Format "yyyy-MM-dd HH:mm:ss") + } + # Add status for already installed applications + if ($exit_code -eq 1603) { + $trackingApp | Add-Member -MemberType NoteProperty -Name "installation_status" -Value "already_installed" + Write-ToLog -message "$appDisplayName appears to be already installed. Adding to tracking file anyway." -log_file $log_file + $success = $true + } + # Handle tracking based on mode + if (-not [string]::IsNullOrWhiteSpace($uninstall_json_file)) { + # GUI mode: append to JSON file immediately + $retryCount = 0 + $maxRetries = 3 + $success_append = $false + while ($retryCount -lt $maxRetries -and -not $success_append) { + try { + # Add a small delay to prevent file access conflicts + if ($retryCount -gt 0) { + Start-Sleep -Milliseconds (100 * $retryCount) + } + Append-ToJson -jsonFilePath $uninstall_json_file -section "external_applications" -newObject $trackingApp + $success_append = $true + Write-ToLog -message "Added/updated $appDisplayName in tracking file for uninstallation" -log_file $log_file + } + catch { + $retryCount++ + Write-ToLog -message "Retry $retryCount/$maxRetries`: Failed to update tracking file for $appDisplayName`: $_" -log_file $log_file + if ($retryCount -eq $maxRetries) { + Write-ToLog -message "Failed to add $appDisplayName to tracking file after $maxRetries attempts" -log_file $log_file + } + } + } + } + # No batch mode: all tracking is immediate per-app + } + + return $success + } + catch { + Write-ToLog -message "Error during installation of $($appDisplayName): $_" -log_file $log_file + return $false + } +} + diff --git a/Windows_Software_Installation/WingetGUI_Installer/Public/Pre_Req.ps1 b/Windows_Software_Installation/WingetGUI_Installer/Public/Pre_Req.ps1 new file mode 100644 index 0000000..eece3a1 --- /dev/null +++ b/Windows_Software_Installation/WingetGUI_Installer/Public/Pre_Req.ps1 @@ -0,0 +1,146 @@ +<# + This script checks to following: + - Terminal is being run with administrator priviledges + - Winget minimum version 1.10.390 is setup + - NuGet Package Provider is installed + - Microsoft winget client + +#> +$green_check = [char]0x2705 +$red_x = [char]0x274C + +<# + Checks to ensure Terminal is being run in admin mode + Returns true if terminal is being run in admin mode + Returns false in all other cases +#> +function CheckIf-Admin() { + $windows_identity = [Security.Principal.WindowsIdentity]::GetCurrent() + $windows_principal = New-Object Security.Principal.WindowsPrincipal($windows_identity) + $is_admin = $windows_principal.IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator) + + if (-not $is_admin) { + return $false + } + return $true +} + + + +<# + Checks the version of winget installed is at least 1.10.390 + Returns true if it is a MINIMUM 1.10.390 + Return false if winget version is lower than 1.10.390 +#> +function Check-Winget() { + $minimum_winget_version = [Version]"1.10.390" + $current_winget_version = winget --version 2>$null + if (-not $current_winget_version) { + return $false + } + $current_winget_version = [Version]($current_winget_version.TrimStart('v')) + if ($current_winget_version -lt $minimum_winget_version) { + return $false + } + else { + return $true + } +} + + + +<# + Checks to ensure that the Microsoft WinGet Client is installed + Returns true if the Winget client module is installed +#> +function Check-WinGet-Client() { + if (Get-InstalledModule -Name "Microsoft.WinGet.Client" -ErrorAction SilentlyContinue) { + return $true + } + else { + return $false + } + +} + +function Check-PreReq() { + if ($Global:external) { + if (-not (CheckIf-Admin)) { + Write-Host "$red_x`: Administrator terminal" + return $false + } + + if (-not (Check-Winget)) { + $user_input = Read-Host "This script requires winget version 1.10.390 minimum to run. Would you like to upgrade? [y/n]" + if ($user_input -eq 'y' -or $user_input -eq "yes" -or $user_input -eq "Y") { + winget upgrade winget + } + else { + Write-Host "Not installing." + return $false + } + } + + + if (-not (Check-WinGet-Client)) { + Write-Host "This script requires the winget client to be installed." -ForegroundColor Yellow + Write-Host "This will also install the NuGet Package Provider." -ForegroundColor Yellow + $user_input = Read-Host "Would you like to install these? [y/n]" + if ($user_input -eq 'y' -or $user_input -eq "yes" -or $user_input -eq "Y") { + Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force + Install-Module -Name Microsoft.WinGet.Client -SkipPublisherCheck -Force + } + else { + Write-Host "Not installing." -ForegroundColor Red + return $false + } + } + + if (CheckIf-Admin -and Check-Winget -and Check-WinGet-Client) { + Write-Host "$green_check`: Administrator terminal." + Write-Host "$green_check`: Winget version 1.10.390 minimum." + Write-Host "$green_check`: Microsoft Winget client installed." + Write-Host "$green_check`: All pre-requisites complete. Proceeding with installation..." + Start-Sleep 2 + return $true + } + } else { + # Internal mode - install silently with error handling + try { + # Try to install NuGet package provider + $nugetInstalled = Get-PackageProvider -Name NuGet -ErrorAction SilentlyContinue + if (-not $nugetInstalled) { + Write-Host "Installing NuGet package provider..." -ForegroundColor Yellow + Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force -Scope CurrentUser -ErrorAction Stop + } else { + Write-Host "NuGet package provider already installed." -ForegroundColor Green + } + } catch { + Write-Host "Warning: Could not install NuGet package provider. Continuing anyway..." -ForegroundColor Yellow + Write-Host "Error: $($_.Exception.Message)" -ForegroundColor Red + } + + try { + # Try to install Microsoft.WinGet.Client module + if (-not (Get-InstalledModule -Name "Microsoft.WinGet.Client" -ErrorAction SilentlyContinue)) { + Write-Host "Installing Microsoft.WinGet.Client module..." -ForegroundColor Yellow + Install-Module -Name Microsoft.WinGet.Client -Force -Scope CurrentUser -ErrorAction Stop + } else { + Write-Host "Microsoft.WinGet.Client module already installed." -ForegroundColor Green + } + } catch { + Write-Host "Warning: Could not install Microsoft.WinGet.Client module. Continuing anyway..." -ForegroundColor Yellow + Write-Host "Error: $($_.Exception.Message)" -ForegroundColor Red + } + + try { + # Try to upgrade winget + Write-Host "Checking for winget updates..." -ForegroundColor Yellow + winget upgrade winget --silent --disable-interactivity --accept-source-agreements 2>$null + } catch { + Write-Host "Warning: Could not upgrade winget. Continuing anyway..." -ForegroundColor Yellow + } + + return $true + } +} \ No newline at end of file diff --git a/Windows_Software_Installation/WingetGUI_Installer/Public/Run_Once_Eula.ps1 b/Windows_Software_Installation/WingetGUI_Installer/Public/Run_Once_Eula.ps1 new file mode 100644 index 0000000..be9741f --- /dev/null +++ b/Windows_Software_Installation/WingetGUI_Installer/Public/Run_Once_Eula.ps1 @@ -0,0 +1,113 @@ +<# + Script that has user accept to all EULA agreements for software installed by this script + Author: Ben Odom (benjamin.j.odom@intel.com) +#> + + +Add-Type -AssemblyName System.Windows.Forms +$disclaimer = @' + +This exclusive remote desktop session includes pre-installed software and models +governed by various end-user license agreements ("EULAs") (the term "Session" refers +to this exclusive remote desktop session and all included software and models). +Please click below for more information: + +By clicking Agree and Continue, I hereby agree and consent to these EULAs. +Intel is providing access to this Session for the sole purpose of demonstrating Intel +technology and enabling me to optimize software for Intel systems, and my use of the +Session is strictly limited to this purpose. I further agree that the +Session is provided by Intel "as is" without any express or implied warranty of any kind. +My use of the Session is at my own risk. Intel will not be liable to me under any legal +theory for any losses or damages in connection with the Session +'@ +$box = New-Object -TypeName System.Windows.Forms.Form +$box.ClientSize = New-Object -TypeName System.Drawing.Size -ArgumentList 600, 380 +$box.Text = "Legal Disclaimer" +$box.StartPosition = "CenterScreen" +$box.ControlBox = $false +$box.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::FixedDialog + +$label = New-Object -TypeName System.Windows.Forms.Label +$label.Location = New-Object -TypeName System.Drawing.Point -ArgumentList 10, 10 +$label.Size = New-Object -TypeName System.Drawing.Size -ArgumentList 450, 260 +$label.Text = $disclaimer +$label.Font = New-Object -TypeName System.Drawing.Font -ArgumentList "Arial", 10 +$label.AutoSize = $true +$label.Padding = New-Object -TypeName System.Windows.Forms.Padding -ArgumentList 10, 10, 10, 10 + +$alink = New-Object -TypeName System.Windows.Forms.LinkLabel +$alink.Text = "Click here for the list of applications and their corresponding EULA" +$alink.Location = New-Object -TypeName System.Drawing.Point -ArgumentList 10, 280 +$alink.Size = New-Object -TypeName System.Drawing.Size -ArgumentList 580, 20 +$alink.LinkBehavior = [System.Windows.Forms.LinkBehavior]::AlwaysUnderline +$alink.Font = New-Object -TypeName System.Drawing.Font -ArgumentList "Arial", 10 +$alink.Add_Click({ + Start-Process -FilePath "https://sdpconnect.intel.com/html/intel_aipc_cloud_access_agreement.htm" + }) + + + +$check_box = New-Object System.Windows.Forms.CheckBox +$check_box.Text = "I have read and understand all the license agreements." +$check_box.AutoSize = $true +$check_box.Location = New-Object System.Drawing.Point -ArgumentList 10, 250 +$box.Controls.Add($check_box) + +# Text to pop up of the button is clicked and the checkbox has not been checked +$check_the_box = New-Object -TypeName System.Windows.Forms.Label +$check_the_box.Location = New-Object -TypeName System.Drawing.Point 10, 230 +$check_the_box.AutoSize = $true +$check_the_box.Text = "Must check the box acknowledging that you have read and understand the terms" +$check_the_box.ForeColor = [System.Drawing.Color]::Red +$check_the_box.Visible = $false +$box.Controls.Add($check_the_box) + + + +$accept_button = New-Object -TypeName System.Windows.Forms.Button +$accept_button.Location = New-Object -TypeName System.Drawing.Point -ArgumentList 150, 310 +$accept_button.Size = New-Object -TypeName System.Drawing.Size -ArgumentList 150, 45 +$accept_button.Text = "Agree and Continue" + +$accept_button.Font = New-Object -TypeName System.Drawing.Font -ArgumentList "Arial", 12 +$accept_button.TextAlign = [System.Windows.Forms.HorizontalAlignment]::Center +$accept_button.Add_Click( { + if ($check_box.Checked) { + # Return true (0) for agree + $box.DialogResult = [System.Windows.Forms.DialogResult]::OK + $box.Close() + } + else { + $check_the_box.Visible = $true + } + }) + + + +$disagree_button = New-Object -TypeName System.Windows.Forms.Button +$disagree_button.Location = New-Object -TypeName System.Drawing.Point -ArgumentList 310, 310 +$disagree_button.Size = New-Object -TypeName System.Drawing.Size -ArgumentList 150, 45 +$disagree_button.Text = "Do not accept" + +$disagree_button.Font = New-Object -TypeName System.Drawing.Font -ArgumentList "Arial", 12 +$disagree_button.TextAlign = [System.Windows.Forms.HorizontalAlignment]::Center +$disagree_button.Add_Click( { + # Return false (!0) for disagree + $box.DialogResult = [System.Windows.Forms.DialogResult]::No + $box.Close() + }) + + +$box.Controls.Add($label) +$box.Controls.Add($alink) +$box.Controls.Add($accept_button) +$box.Controls.Add($disagree_button) + +# Show the dialog box and return the result +$box.ShowDialog() | Out-Null +# Return the dialog result +if ($box.DialogResult -eq [System.Windows.Forms.DialogResult]::OK) { + exit 0 +} else { + exit 1 +} \ No newline at end of file diff --git a/Windows_Software_Installation/WingetGUI_Installer/Public/Uninstall.ps1 b/Windows_Software_Installation/WingetGUI_Installer/Public/Uninstall.ps1 new file mode 100644 index 0000000..7193cce --- /dev/null +++ b/Windows_Software_Installation/WingetGUI_Installer/Public/Uninstall.ps1 @@ -0,0 +1,390 @@ +# Uninstall.ps1 +# Module containing all uninstallation-related functions + +# Test if a winget uninstallation was successful +function Test-UninstallationSuccess { + param ( + [int]$exit_code, + [string]$app_name, + [string]$log_file + ) + + switch ($exit_code) { + 0 { + Write-ToLog -message "Successfully uninstalled $app_name" -log_file $log_file + return $true + } + -1978335189 { + Write-ToLog -message "Application $app_name is not installed" -log_file $log_file + return $true # Still return success, since the goal is for the app to not be installed + } + -1978335188 { + Write-ToLog -message "No applicable uninstaller found for $app_name" -log_file $log_file + return $true # Consider it success, since we can't uninstall what doesn't exist + } + -1978335186 { + Write-ToLog -message "Uninstallation of $app_name was blocked by policy" -log_file $log_file + return $false + } + -1978335185 { + Write-ToLog -message "No packages found to uninstall for $app_name" -log_file $log_file + return $true # Still return success, since the goal is for the app to not be installed + } + 3010 { + Write-ToLog -message "Successfully uninstalled $app_name (reboot required)" -log_file $log_file + return $true + } + 1641 { + Write-ToLog -message "Successfully uninstalled $app_name (initiated reboot)" -log_file $log_file + return $true + } + default { + Write-ToLog -message "Uninstallation of $app_name completed with exit code: $exit_code" -log_file $log_file + return $exit_code -eq 0 # For any other code, return true only if it's 0 + } + } +} + +# Used by the GUI to uninstall selected packages +function Uninstall-SelectedPackages { + param ( + [array]$selectedPackages, + [string]$log_file, + [string]$json_uninstall_file_path + ) + + # Prepare result tracking + $results = @{ + TotalPackages = $selectedPackages.Count + SuccessfulUninstalls = 0 + FailedUninstalls = 0 + FailedPackages = @() + } + + foreach ($package in $selectedPackages) { + # Create app object from the package information in the datatable + if ($package.Type -eq "Winget") { + $app = [PSCustomObject]@{ + id = $package.Id + friendly_name = $package.FriendlyName + version = if ($package.Version -eq "Latest") { $null } else { $package.Version } + } + $section = "winget_applications" + $id = $package.Id + } else { + $app = [PSCustomObject]@{ + name = $package.Id + friendly_name = $package.FriendlyName + version = if ($package.Version -eq "Latest") { $null } else { $package.Version } + } + $section = "external_applications" + $id = $package.Id + } + + # For external applications, look up the full details including uninstall_command + if ($package.Type -eq "External") { + $uninstallJson = Get-Content -Path $json_uninstall_file_path -Raw | ConvertFrom-Json + $originalApp = $uninstallJson.external_applications | Where-Object { $_.name -eq $app.name } | Select-Object -First 1 + if ($originalApp) { + $app = $originalApp + } + } + + try { + if ($app.PSObject.Properties.Name -contains "uninstall_command") { + $success = Uninstall-ExternalApplication -app $app -log_file $log_file + } else { + $success = Uninstall-WingetApplication -app $app -log_file $log_file + } + + if ($success) { + $results.SuccessfulUninstalls++ + # Remove from uninstall.json after successful uninstall + Remove-FromJsonById -jsonFilePath $json_uninstall_file_path -section $section -id $id + } else { + $results.FailedUninstalls++ + $appName = if ($app.friendly_name) { $app.friendly_name } else { if ($app.id) { $app.id } else { $app.name } } + $results.FailedPackages += $appName + } + } catch { + $appIdentifier = if ($app.id) { $app.id } else { $app.name } + Write-ToLog -message "Error uninstalling $appIdentifier`: $_" -log_file $log_file + $results.FailedUninstalls++ + $appName = if ($app.friendly_name) { $app.friendly_name } else { $appIdentifier } + $results.FailedPackages += $appName + } + } + + return $results +} + +# Uninstall a winget application +function Uninstall-WingetApplication { + param ( + [PSCustomObject]$app, + [string]$log_file + ) + + # Validate app object has required properties + if (-not $app -or (-not $app.id -and -not $app.name)) { + Write-ToLog -message "Error: Invalid application object provided to Uninstall-WingetApplication. Must have id or name property." -log_file $log_file + return $false + } + + # Determine the application identifier to use (prefer id, fall back to name) + $appIdentifier = if ($app.id) { $app.id } else { $app.name } + $appDisplayName = if ($app.friendly_name) { $app.friendly_name } else { $appIdentifier } + + # Log what we're about to uninstall + Write-ToLog -message "Uninstalling application: $appDisplayName $(if ($app.version) { "version $($app.version)" } else { "(any version)" })" -log_file $log_file + + # Construct arguments for winget uninstallation with comprehensive silent flags + $arguments = @( + "uninstall", + "--purge", + "--accept-source-agreements", + "--silent", + "--disable-interactivity", + "--force" # Force uninstall without confirmation dialogs + ) + + # Add the application ID + $arguments += @("--id", $appIdentifier) + + if ($app.version -and $app.version -ne "Latest" -and $app.version -ne "" -and $app.version -ne $null) { + $arguments += @("-v", $app.version) + } + + # Add uninstall override flags if they exist for this application + if ($app.uninstall_override_flags) { + $arguments += @("--override", $app.uninstall_override_flags) + Write-ToLog -message "Using custom uninstall override flags for ${appDisplayName}: $($app.uninstall_override_flags)" -log_file $log_file + } + + Write-ToLog -message "Uninstalling $appDisplayName" -log_file $log_file + + # Set comprehensive environment variables to suppress ALL UI elements + $env:WINGET_DISABLE_INTERACTIVITY = "1" + $env:WINGET_DISABLE_UPGRADE_PROMPTS = "1" + $env:WINGET_DISABLE_CONFIRMATION = "1" + $env:SILENT = "1" + $env:QUIET = "1" + + # Log the full command we're about to execute + $commandStr = "winget $($arguments -join ' ')" + Write-ToLog -message "Executing command: $commandStr" -log_file $log_file + + try { + $process = Start-Process -FilePath winget -ArgumentList $arguments -PassThru -Wait -NoNewWindow + $exit_code = $process.ExitCode + + return Test-UninstallationSuccess -exit_code $exit_code -app_name $appDisplayName -log_file $log_file + } + catch { + Write-ToLog -message "Error during uninstallation of ${appDisplayName}: $_" -log_file $log_file + return $false + } +} + +# Uninstall an external application +function Uninstall-ExternalApplication { + param ( + [PSCustomObject]$app, + [string]$log_file + ) + + # Get display name for logging + $appDisplayName = if ($app.friendly_name) { $app.friendly_name } else { $app.name } + + # Validate app object has required properties + if (-not $app -or -not $app.name) { + Write-ToLog -message "Error: Invalid application object for external application" -log_file $log_file + return $false + } + + if (-not $app.uninstall_command) { + Write-ToLog -message "Warning: No uninstall command provided for $appDisplayName. Considering it already uninstalled." -log_file $log_file + return $true # Return success since there's nothing to uninstall + } + + Write-ToLog -message "Uninstalling external application: $appDisplayName" -log_file $log_file + Write-ToLog -message "Using command: $($app.uninstall_command)" -log_file $log_file + + $regex = '([a-zA-Z]:.*.exe)(.*)' # Regex to match the uninstall command + if ($app.uninstall_command -match $regex) { + $command = $matches[1] + $arguments_unsplit = $matches[2] + + # Check if the executable exists + if (-not (Test-Path -Path $command)) { + Write-ToLog -message "Warning: Uninstall executable not found at: $command for $appDisplayName. Considering it already uninstalled." -log_file $log_file + return $true # Return success since there's nothing to uninstall + } + + # Split the arguments properly + $arguments_split = @() + if (-not [string]::IsNullOrWhiteSpace($arguments_unsplit)) { + $arguments_split = $arguments_unsplit -split ' (?=(?:[^\\"]*\\"[^\\"]*\\")*[^\\"]*$)' | + Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | + ForEach-Object { $_.Trim('\\"') } + } + + Write-ToLog -message "Parsed command: $command" -log_file $log_file + Write-ToLog -message "Parsed arguments: $($arguments_split -join ', ')" -log_file $log_file + + try { + $process = Start-Process -FilePath $command -ArgumentList $arguments_split -PassThru -Wait -NoNewWindow + $exit_code = $process.ExitCode + Write-ToLog -message "Uninstalled $appDisplayName with exit code $exit_code" -log_file $log_file + + # Consider any exit code as success for external applications, as different installers use different codes + # For applications like Visual Studio, the uninstaller might return a non-zero exit code even on success + if ($exit_code -eq 0) { + return $true + } else { + # Check known "success" exit codes from common uninstallers + $successExitCodes = @(0, 3010, 1641) # 3010 = Reboot required, 1641 = Initiated reboot + if ($successExitCodes -contains $exit_code) { + Write-ToLog -message "Uninstallation of $appDisplayName successful with expected exit code $exit_code" -log_file $log_file + return $true + } else { + Write-ToLog -message "Uninstallation of $appDisplayName may have failed with exit code $exit_code" -log_file $log_file + # Return true anyway to remove from tracking file, as we can't reliably determine failure for external apps + return $true + } + } + } + catch { + Write-ToLog -message "Error during uninstallation of external application ${appDisplayName}: $_" -log_file $log_file + return $false + } + } + else { + Write-ToLog -message "Invalid uninstall command format for ${appDisplayName}: $($app.uninstall_command)" -log_file $log_file + return $false + } +} + +# Batch uninstallation function used by the command-line mode +function Invoke-BatchUninstall { + param ( + [string]$json_uninstall_file_path, + [string]$uninstall_log_file + ) + + Write-Host "Starting batch uninstallation process..." -ForegroundColor Cyan + Write-ToLog -message "Starting batch uninstallation from $json_uninstall_file_path" -log_file $uninstall_log_file + + # Check if the uninstall JSON file exists + if (-not (Test-Path -Path $json_uninstall_file_path)) { + $errorMsg = "Uninstall JSON file not found at: $json_uninstall_file_path" + Write-Host $errorMsg -ForegroundColor Red + Write-ToLog -message $errorMsg -log_file $uninstall_log_file + return + } + + # Try to read the uninstall JSON file + try { + $applications = Get-Content -Path $json_uninstall_file_path -Raw | ConvertFrom-Json + Write-Host "Successfully loaded uninstall data" -ForegroundColor Green + } + catch { + $errorMsg = "Error reading uninstall JSON file: $_" + Write-Host $errorMsg -ForegroundColor Red + Write-ToLog -message $errorMsg -log_file $uninstall_log_file + return + } + + # Initialize success trackers + $successfulWingetUninstalls = 0 + $failedWingetUninstalls = 0 + $successfulExternalUninstalls = 0 + $failedExternalUninstalls = 0 + + # Import Remove-FromJsonById from Append-ToJson.ps1 if not already available + if (-not (Get-Command Remove-FromJsonById -ErrorAction SilentlyContinue)) { + $appendToJsonPath = Join-Path -Path (Split-Path $PSScriptRoot -Parent) -ChildPath "Public\Append-ToJson.ps1" + if (Test-Path $appendToJsonPath) { + . $appendToJsonPath + } + } + + # Uninstall winget applications + if ($applications.winget_applications -and $applications.winget_applications.Count -gt 0) { + Write-Host "Uninstalling $($applications.winget_applications.Count) winget applications..." -ForegroundColor Cyan + Write-ToLog -message "Uninstalling $($applications.winget_applications.Count) winget applications" -log_file $uninstall_log_file + + foreach ($app in $applications.winget_applications) { + $appName = if ($app.friendly_name) { $app.friendly_name } else { if ($app.id) { $app.id } else { $app.name } } + Write-Host "Uninstalling winget application: $appName" -ForegroundColor Cyan + + $success = Uninstall-WingetApplication -app $app -log_file $uninstall_log_file + if ($success) { + $successfulWingetUninstalls++ + # Remove from uninstall.json immediately after uninstall + Remove-FromJsonById -jsonFilePath $json_uninstall_file_path -section "winget_applications" -id $app.id + Write-Host "Successfully uninstalled and removed from tracking: $appName" -ForegroundColor Green + } else { + $failedWingetUninstalls++ + Write-Host "Failed to uninstall: $appName" -ForegroundColor Red + } + } + } else { + Write-Host "No winget applications found to uninstall" -ForegroundColor Yellow + Write-ToLog -message "No winget applications found to uninstall" -log_file $uninstall_log_file + } + + # Uninstall external applications + if ($applications.external_applications -and $applications.external_applications.Count -gt 0) { + Write-Host "Uninstalling $($applications.external_applications.Count) external applications..." -ForegroundColor Cyan + Write-ToLog -message "Uninstalling $($applications.external_applications.Count) external applications" -log_file $uninstall_log_file + + foreach ($app in $applications.external_applications) { + $appName = if ($app.friendly_name) { $app.friendly_name } else { $app.name } + Write-Host "Uninstalling external application: $appName" -ForegroundColor Cyan + + $success = Uninstall-ExternalApplication -app $app -log_file $uninstall_log_file + if ($success) { + $successfulExternalUninstalls++ + # Remove from uninstall.json immediately after uninstall + Remove-FromJsonById -jsonFilePath $json_uninstall_file_path -section "external_applications" -id $app.name + Write-Host "Successfully uninstalled and removed from tracking: $appName" -ForegroundColor Green + } else { + $failedExternalUninstalls++ + Write-Host "Failed to uninstall: $appName" -ForegroundColor Red + } + } + } else { + Write-Host "No external applications found to uninstall" -ForegroundColor Yellow + Write-ToLog -message "No external applications found to uninstall" -log_file $uninstall_log_file + } + + # At this point, Remove-FromJsonById will have deleted uninstall.json if all apps are removed. + # If the file still exists, update it (for any failed uninstalls) + if (Test-Path $json_uninstall_file_path) { + try { + $applications = Get-Content -Path $json_uninstall_file_path -Raw | ConvertFrom-Json + $applications | ConvertTo-Json -Depth 4 | Set-Content -Path $json_uninstall_file_path -Force + Write-Host "Updated uninstall tracking file" -ForegroundColor Green + Write-ToLog -message "Updated uninstall tracking file" -log_file $uninstall_log_file + } + catch { + Write-Host "Error updating uninstall tracking file: $_" -ForegroundColor Red + Write-ToLog -message "Error updating uninstall tracking file: $_" -log_file $uninstall_log_file + } + } else { + Write-Host "Uninstall tracking file removed (all apps uninstalled)." -ForegroundColor Green + Write-ToLog -message "Uninstall tracking file removed (all apps uninstalled)." -log_file $uninstall_log_file + } + + # Summarize results + Write-Host "`nUninstallation Summary:" -ForegroundColor Yellow + Write-Host "--------------------" -ForegroundColor Yellow + Write-Host "Winget Applications: $successfulWingetUninstalls successful, $failedWingetUninstalls failed" -ForegroundColor White + Write-Host "External Applications: $successfulExternalUninstalls successful, $failedExternalUninstalls failed" -ForegroundColor White + Write-Host "Total: $($successfulWingetUninstalls + $successfulExternalUninstalls) successful, $($failedWingetUninstalls + $failedExternalUninstalls) failed" -ForegroundColor White + + # Log summary + Write-ToLog -message "Uninstallation Summary: $successfulWingetUninstalls winget apps successful, $failedWingetUninstalls failed" -log_file $uninstall_log_file + Write-ToLog -message "Uninstallation Summary: $successfulExternalUninstalls external apps successful, $failedExternalUninstalls failed" -log_file $uninstall_log_file +} diff --git a/Windows_Software_Installation/WingetGUI_Installer/Public/Write_ToLog.ps1 b/Windows_Software_Installation/WingetGUI_Installer/Public/Write_ToLog.ps1 new file mode 100644 index 0000000..750422a --- /dev/null +++ b/Windows_Software_Installation/WingetGUI_Installer/Public/Write_ToLog.ps1 @@ -0,0 +1,16 @@ +<# + Helper function to just write to any given log, with timestamp included + Creates file if it does not exist already +#> +function Write-ToLog { + param ( + [string]$message, + [string]$log_file + ) + $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" + # Create file if it doesn't exist + if (-not (Test-Path -Path $log_file)) { + New-Item -Path $log_file -ItemType File + } + "$timestamp - $message" | Out-File -FilePath $log_file -Append +} \ No newline at end of file diff --git a/Windows_Software_Installation/WingetGUI_Installer/Setup_1.ps1 b/Windows_Software_Installation/WingetGUI_Installer/Setup_1.ps1 new file mode 100644 index 0000000..8d75168 --- /dev/null +++ b/Windows_Software_Installation/WingetGUI_Installer/Setup_1.ps1 @@ -0,0 +1,591 @@ +# This script is designed to set up a development environment on Windows using winget. +# It installs or updates a list of applications, including Visual Studio, Python, and others. +# It also sets the execution policy to Unrestricted to allow script execution. +# **********************************************# +# IMPORTANT: This script must be run from an elevated PowerShell prompt. +# Usage: +# If execution policy prevents scripts from running, use: +# powershell.exe -ExecutionPolicy RemoteSigned -File ".\Setup_1.ps1" install +# powershell.exe -ExecutionPolicy RemoteSigned -File ".\Setup_1.ps1" gui +# Or set policy first: Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser -Force +# ./Setup_1.ps1 install -> Installs software (command line mode) +# ./Setup_1.ps1 gui -> Shows GUI for interactive package selection and installation/uninstallation +# ./Setup_1.ps1 uninstall -> Uninstalls software +# ***************************************** # +<# +.SYNOPSIS + Setup script for development environment installation using winget. + +.DESCRIPTION + This script automates the installation of development tools and software + using the Windows Package Manager (winget). It supports both GUI and command-line + modes for installation and uninstallation. + +.PARAMETER command + Specifies the operation mode: 'install', 'gui', or 'uninstall'. + +.EXAMPLE + .\Setup_1.ps1 gui + Launches the graphical interface for interactive software selection. + +.EXAMPLE + .\Setup_1.ps1 install + Installs all software defined in the applications.json file. + +.EXAMPLE + .\Setup_1.ps1 uninstall + Uninstalls previously installed software tracked in uninstall.json. + +.NOTES + Requires Administrator privileges to run. + Authors: + - Vijay (vijay.chandrashekar@intel.com) + - Ram (vaithi.s.ramadoss@intel.com) + - Ben (benjamin.j.odom@intel.com) +#> +param( + [Parameter(Position=0)] + [string]$command # Accepts a command parameter: install, gui, or uninstall +) + + +# ===================== GENERIC IMPORTANT INSTALLATION WARNING ===================== +Write-Host "=======================================================================================" -ForegroundColor Yellow +Write-Host "*** IMPORTANT ACTION REQUIRED: If you have any existing applications already installed," -ForegroundColor White -BackgroundColor DarkRed +Write-Host "please uninstall them first and then use this utility to install. Installing the same " -ForegroundColor White -BackgroundColor DarkRed +Write-Host "application in two different ways may cause conflicts and the application may not work as" -ForegroundColor White -BackgroundColor DarkRed +Write-Host "expected. User discretion is mandatory. ***" -ForegroundColor White -BackgroundColor DarkRed +Write-Host "" +Write-Host "" +Write-Host "*** Recommended System Requirements: This SDK will work best on systems that contain " -ForegroundColor White -BackgroundColor Blue +Write-Host ""Intel`u{00AE} Core`u{2122} Ultra processors and Intel Arc`u{2122}" GPUs, it will work on other products but " -ForegroundColor White -BackgroundColor Blue +Write-Host "not all features will be supported. ***" -ForegroundColor White -BackgroundColor Blue +Write-Host "=======================================================================================" -ForegroundColor Yellow +Write-Host "" +Write-Host "" +Write-Host "Waiting 5 seconds for you to review this warning..." -ForegroundColor Yellow +Start-Sleep -Seconds 5 + +# Ensure execution policy allows script execution (do this first) +try { + $currentPolicy = Get-ExecutionPolicy -Scope CurrentUser + if ($currentPolicy -eq "Restricted" -or $currentPolicy -eq "AllSigned") { + Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser -Force + Write-Host "Updated execution policy from $currentPolicy to RemoteSigned for CurrentUser" -ForegroundColor Yellow + } +} +catch { + Write-Host "Warning: Could not set execution policy: $_" -ForegroundColor Yellow +} + +# Process command parameters - handle both dash and no-dash formats +if ($command -match "^-{1,2}(\w+)$") { + $command = $matches[1] # Extract the command name without dashes +} + +Write-Host "Running in mode: $command" -ForegroundColor Cyan + +<# + Global variables +#> +# If external = $true, this means the script is for the customer, meaning they must accept the EULA pop-up +# If external = $false, this means it is "internal", the user will NOT have to accept the EULA pop-up +# By switching this to false YOU acknowledge that this script will NOT be provided toward customers to be used on their own personal machines +$Global:external = $false # Indicates whether the script is for external use, affecting EULA acceptance +$task_name = "AIPCCloud ENV Setup" # Name of the scheduled task for environment setup + +<# + Administrator privilege checking +#> +function Test-Administrator { +# Check for at least 100GB free disk space before proceeding +function Test-FreeDiskSpace { + [CmdletBinding()] + [OutputType([bool])] + param( + [Parameter(Mandatory=$false)] + [int]$minGB = 100 + ) + $drive = (Get-Location).Path.Substring(0,1) + $freeSpaceGB = [math]::Round((Get-PSDrive -Name $drive).Free/1GB,2) + Write-Host "=============================================================" -ForegroundColor Yellow + Write-Host "Disk space available on $($drive): $freeSpaceGB GB" -ForegroundColor Magenta + if ($freeSpaceGB -lt $minGB) { + Write-Host "!!! RECOMMENDED: At least $minGB GB of free disk space for smooth installation !!!" -ForegroundColor Red -BackgroundColor Yellow + Write-Host "Only $freeSpaceGB GB available. You may proceed, but issues may occur if space runs out." -ForegroundColor Yellow + Write-Host "Waiting 5 seconds for you to review this warning..." -ForegroundColor Yellow + Start-Sleep -Seconds 5 + } else { + Write-Host "You have adequate disk space to continue installation." -ForegroundColor Green + } + Write-Host "=============================================================" -ForegroundColor Yellow + +} + +# Run disk space check before any installation or GUI mode +if ($command -eq 'install' -or $command -eq 'gui') { + Test-FreeDiskSpace +} + $currentUser = [Security.Principal.WindowsIdentity]::GetCurrent() + $principal = New-Object Security.Principal.WindowsPrincipal($currentUser) + return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) +} + +function Request-AdminPrivileges { + [CmdletBinding()] + param( + [Parameter(Mandatory=$false)] + [string]$commandToRun = "" + ) + + if (-not (Test-Administrator)) { + Add-Type -AssemblyName System.Windows.Forms + $result = [System.Windows.Forms.MessageBox]::Show( + "This application requires administrator privileges to install software.`n`nWould you like to restart as administrator?", + 'Administrator Required', + [System.Windows.Forms.MessageBoxButtons]::YesNo, + [System.Windows.Forms.MessageBoxIcon]::Warning + ) + + if ($result -eq 'Yes') { + # Restart as administrator + $scriptPath = $PSCommandPath + if (-not $scriptPath) { + $scriptPath = $MyInvocation.MyCommand.Path + } + + $argumentList = if ($commandToRun) { "-ExecutionPolicy RemoteSigned -File `"$scriptPath`" $commandToRun" } else { "-ExecutionPolicy RemoteSigned -File `"$scriptPath`"" } + Start-Process -FilePath "powershell.exe" -ArgumentList $argumentList -Verb RunAs + } + + # Exit current instance + exit + } +} + +Set-Location -Path $PSScriptRoot # Sets the current directory to the script's location +$logs_dir = "C:\temp\logs" # Directory for storing log files +$json_dir = ".\json" # Directory for storing JSON files + +# Ensure C:\temp directory exists +if (-not (Test-Path -Path "C:\temp")) { + New-Item -Path "C:\temp" -ItemType Directory -Force | Out-Null + Write-Host "Created C:\temp directory for logs" -ForegroundColor Yellow +} + +# Source helper scripts +. ".\Public\Write_ToLog.ps1" # Sources a script for logging messages +. ".\Public\Append-ToJson.ps1" # Sources a script for appending data to JSON files +. ".\Public\Pre_Req.ps1" # Sources a script for checking pre-requisites +. ".\Public\GUI.ps1" # Sources GUI functions +. ".\Public\Install.ps1" # Sources installation functions +. ".\Public\Uninstall.ps1" # Sources uninstallation functions + +<# + Initializes logs for installation +#> +function Initialize-Directory { + [CmdletBinding()] + param( + [Parameter(Mandatory=$true)] + [string]$location + ) + + if (-not (Test-Path -Path $location)) { + New-Item -Path $location -ItemType Directory | Out-Null # Creates a directory if it doesn't exist + } +} + + +<# + Creates a file at the given location +#> +function New-File { + [CmdletBinding()] + param( + [Parameter(Mandatory=$true)] + [string]$location + ) + + if (-not (Test-Path -Path $location)) { + New-Item -Path $location -ItemType File | Out-Null # Creates a file if it doesn't exist + } +} + + +<# + Calls script for user to accept EULA agreements for ALL software this script installs + Returns true if they accept, false otherwise +#> +function Confirm-Eula { + [CmdletBinding()] + [OutputType([bool])] + param() + + # Source Script + $run_once = ".\Public\Run_Once_Eula.ps1" # Path to the EULA acceptance script + & $run_once # Executes the EULA acceptance script + return $? # Returns the exit status of the EULA script +} + +try { + + # Check for administrator privileges for GUI, install, and uninstall commands + if ($command -eq "gui" -or $command -eq "install" -or $command -eq "uninstall") { + Request-AdminPrivileges -commandToRun $command + } + + # Log directory structure + $install_logs_dir = "$logs_dir\install" # Directory for installation logs + $uninstall_logs_dir = "$logs_dir\uninstall" # Directory for uninstallation logs + $error_logs_dir = "$logs_dir\error" # Directory for error logs + + # Logs text file locations + $install_log_file = "$install_logs_dir\install_log.txt" # File for installation logs + $uninstall_log_file = "$uninstall_logs_dir\uninstall.txt" # File for uninstallation logs + $error_log_file = "$error_logs_dir\error_log.txt" # File for error logs + + # Json file structure + $json_install_dir = "$json_dir\install" # Directory for installation JSON files + $json_uninstall_dir = "$json_dir\uninstall" # Directory for uninstallation JSON files + $json_install_file_path = "$json_install_dir\applications.json" # Path to the applications JSON file + $json_uninstall_file_path = "$json_uninstall_dir\uninstall.json" # Path to the uninstallation JSON file + + # ============================== Reading JSON and organizing items ===================== + + # Read items from applications.json + + if ($command -eq "gui") { + # GUI mode for interactive package selection + + # Setup logging directories and files for both install and uninstall operations + Initialize-Directory $install_logs_dir + Initialize-Directory $error_logs_dir + Initialize-Directory $uninstall_logs_dir + New-File $install_log_file + New-File $error_log_file + New-File $uninstall_log_file + + # Setup uninstall json file + Initialize-Directory $json_uninstall_dir + + # Check for pre-requisites + $pre_req = Check-PreReq + if (-not $pre_req) { + Add-Type -AssemblyName System.Windows.Forms + [System.Windows.Forms.MessageBox]::Show( + "Pre-requisites not met. Please ensure winget is available.", + 'Environment Setup - Error', + [System.Windows.Forms.MessageBoxButtons]::OK, + [System.Windows.Forms.MessageBoxIcon]::Error + ) + exit 1 + } + + # If running externally, have user agree to EULA pop-up + if ($Global:external) { + if (-not (Confirm-Eula)) { + Add-Type -AssemblyName System.Windows.Forms + [System.Windows.Forms.MessageBox]::Show( + "EULA not accepted. Installation cancelled.", + 'Environment Setup', + [System.Windows.Forms.MessageBoxButtons]::OK, + [System.Windows.Forms.MessageBoxIcon]::Information + ) + exit 1 + } + else { + $host_name = hostname + Write-ToLog -message "Hostname: $host_name has accepted the EULA Agreement" -log_file $install_log_file + } + } + + $applications = Get-Content -Path $json_install_file_path -Raw | ConvertFrom-Json + + # Prep winget so no hanging + winget list --accept-source-agreements > $null 2>&1 + + # Show main GUI menu + Show-MainGUI -applications $applications -install_log_file $install_log_file -json_uninstall_file_path $json_uninstall_file_path + } + elseif ($command -eq "install") { + + # Setup logging directories and files + Initialize-Directory $install_logs_dir + Initialize-Directory $error_logs_dir + New-File $install_log_file + New-File $error_log_file + + # Create JSON directory for uninstall files if it doesn't exist + Initialize-Directory $json_uninstall_dir + New-File $json_uninstall_file_path + + # Create the base JSON structure in the uninstall file + $json_structure = @{ + "winget_applications" = @() + "external_applications" = @() + } + $json_structure | ConvertTo-Json | Set-Content -Path $json_uninstall_file_path + + # Check for pre-requisites + $pre_req = Check-PreReq # Calls a function to check pre-requisites + if ($pre_req) { + Write-ToLog -message "All pre-requisites complete. Installing." -log_file $install_log_file + } + else { + Write-ToLog -message "Pre-requisites not met. Exiting." -log_file $install_log_file + Write-Host "Pre-requisites not met. Exiting." -ForegroundColor Red + exit 1 # Exits the script if pre-requisites are not met + } + + # If running externally, have user agree to EULA pop-up + if ($Global:external) { + + if (-not (Confirm-Eula)) { + Write-Host "Eula not accepted. Exiting." -ForegroundColor Red + Write-ToLog -message "Eula not accepted. Exiting." -log_file $install_log_file + exit 1 # Exits the script if EULA is not accepted + } + else { + Write-Host "Eula accepted. Proceeding." -ForegroundColor Green + $host_name = hostname + Write-ToLog -message "Hostname: $host_name has accepted the EULA Agreement" -log_file $install_log_file + } + } + + # Debug JSON file path + Write-Host "Debug: Loading JSON from path: $json_install_file_path" -ForegroundColor Magenta + if (Test-Path -Path $json_install_file_path) { + Write-Host "Debug: JSON file exists" -ForegroundColor Magenta + try { + $applications = Get-Content -Path $json_install_file_path -Raw | ConvertFrom-Json # Reads and parses the JSON file + Write-Host "Debug: JSON file loaded successfully" -ForegroundColor Magenta + + # Print out which items are going to be downloaded (skip_install != yes) + $toInstall = $applications.winget_applications | Where-Object { -not $_.skip_install -or $_.skip_install.ToString().ToLower() -ne 'yes' } + Write-Host "Preparing to install the following applications:" -ForegroundColor Yellow + foreach ($app in $toInstall) { + $app_id = if ($app.id) { $app.id } else { $app.name } + $friendly_name = if ($app.friendly_name) { $app.friendly_name } else { $app_id } + Write-Host "- $friendly_name ($app_id) - Source: Winget" -ForegroundColor Green + if ($null -ne $app.dependencies) { + Write-Host " Dependencies:" -ForegroundColor Blue + foreach ($dep in $app.dependencies) { + Write-Host " - $($dep.name) v$($dep.version)" -ForegroundColor Blue + } + } + } + } catch { + Write-Host "Debug: Error loading JSON file: $_" -ForegroundColor Red + Write-Host "Current directory: $(Get-Location)" -ForegroundColor Magenta + Write-Host "JSON file path: $json_install_file_path" -ForegroundColor Magenta + exit 1 + } + } else { + Write-Host "Debug: JSON file does not exist at path: $json_install_file_path" -ForegroundColor Red + Write-Host "Current directory: $(Get-Location)" -ForegroundColor Magenta + Write-Host "Checking parent directories..." -ForegroundColor Magenta + $alternativePath = "$PSScriptRoot\..\JSON\install\applications.json" + if (Test-Path -Path $alternativePath) { + Write-Host "Found JSON at alternative path: $alternativePath" -ForegroundColor Green + $json_install_file_path = $alternativePath + $applications = Get-Content -Path $json_install_file_path -Raw | ConvertFrom-Json + + # Print out which items are going to be downloaded + Write-Host "Preparing to install the following applications:" -ForegroundColor Yellow + foreach ($app in $applications.winget_applications) { + $app_id = if ($app.id) { $app.id } else { $app.name } + $friendly_name = if ($app.friendly_name) { $app.friendly_name } else { $app_id } + Write-Host "- $friendly_name ($app_id) - Source: Winget" -ForegroundColor Green + if ($null -ne $app.dependencies) { + Write-Host " Dependencies:" -ForegroundColor Blue + foreach ($dep in $app.dependencies) { + Write-Host " - $($dep.name) v$($dep.version)" -ForegroundColor Blue + } + } + } + } else { + Write-Host "Alternative path also not found. Exiting." -ForegroundColor Red + exit 1 + } + } + + $toInstallExternal = $applications.external_applications | Where-Object { -not $_.skip_install -or $_.skip_install.ToString().ToLower() -ne 'yes' } + Write-Host "Additional external applications" -ForegroundColor Yellow + foreach ($app in $toInstallExternal) { + $friendly_name = if ($app.friendly_name) { $app.friendly_name } else { $app.name } + Write-Host "- $friendly_name ($($app.name)) - Source: External" -ForegroundColor Green + if ($null -ne $app.dependencies) { + Write-Host " Dependencies:" -ForegroundColor Blue + foreach ($dep in $app.dependencies) { + Write-Host " - $($dep.name) v$($dep.version)" -ForegroundColor Blue + } + } + } + + # Prep winget so no hanging + winget list --accept-source-agreements > $null 2>&1 # Prepares winget by accepting source agreements + + # Get installed packages to check dependencies + $winget_list = Get-WinGetPackage # Retrieves the list of installed winget packages + + # Check dependencies + foreach ($app in $applications.winget_applications) { + if ($null -ne $app.dependencies) { + foreach ($dep in $app.dependencies) { + $depName = $dep.name + + # Check if dependency is already in the list of applications to install + $dependencyApp = $applications.winget_applications | Where-Object { + ($_.id -match $depName) -or ($_.name -match $depName) -or ($_.friendly_name -match $depName) + } + + if ($null -eq $dependencyApp) { + # Check if dependency is already installed on the system + $isInstalled = $winget_list | Where-Object { $_.Name -match $depName } + + if ($null -eq $isInstalled) { + Write-Host "Dependency $depName required for $app_id is not installed and not in the install list. Skipping $app_id" -ForegroundColor Yellow + # Remove the application from the list if its dependency can't be met + $applications.winget_applications = $applications.winget_applications | Where-Object { + ($_.id -ne $app_id) -and ($_.name -ne $app_id) + } + } + } + } + } + } + + # Invoke the installation process (per-app tracking, pass loaded app arrays) + # Install winget applications + if ($applications.winget_applications) { + $wingetToInstall = $applications.winget_applications | Where-Object { -not $_.skip_install -or $_.skip_install.ToString().ToLower() -ne 'yes' } + if ($wingetToInstall.Count -gt 0) { + Install-SelectedPackages -selectedPackages $wingetToInstall -log_file $install_log_file -uninstall_json_file $json_uninstall_file_path + } + } + + # Install external applications + if ($applications.external_applications) { + $externalToInstall = $applications.external_applications | Where-Object { -not $_.skip_install -or $_.skip_install.ToString().ToLower() -ne 'yes' } + if ($externalToInstall.Count -gt 0) { + Install-SelectedPackages -selectedPackages $externalToInstall -log_file $install_log_file -uninstall_json_file $json_uninstall_file_path + } + } + + # Copy install logs to desktop + $username = [Environment]::UserName + Copy-Item -Path $install_log_file -Destination "C:\Users\$username\Desktop\install_logs.txt" # Copies the install log to the user's desktop + + # Check if uninstall.json was created and show summary + if (Test-Path -Path $json_uninstall_file_path) { + Write-Host "Uninstall.json created successfully at: $json_uninstall_file_path" -ForegroundColor Green + $uninstallData = Get-Content -Path $json_uninstall_file_path -Raw | ConvertFrom-Json + $wingetCount = if ($uninstallData.winget_applications) { $uninstallData.winget_applications.Count } else { 0 } + $externalCount = if ($uninstallData.external_applications) { $uninstallData.external_applications.Count } else { 0 } + Write-Host "Tracked for uninstall: $wingetCount winget apps, $externalCount external apps" -ForegroundColor Yellow + } else { + Write-Host "Warning: Uninstall.json was not created!" -ForegroundColor Red + } + + if (-not $Global:external) { + # Check if the scheduled task exists before trying to unregister it + try { + $existingTask = Get-ScheduledTask -TaskName $task_name -ErrorAction SilentlyContinue + if ($existingTask) { + Unregister-ScheduledTask -TaskName $task_name -Confirm:$false + Write-ToLog -message "Successfully unregistered scheduled task: $task_name" -log_file $install_log_file + } else { + Write-ToLog -message "Scheduled task '$task_name' not found - nothing to unregister" -log_file $install_log_file + } + } + catch { + Write-ToLog -message "Failed to unregister scheduled task: $($_.Exception.Message)" -log_file $install_log_file + Write-Host "Warning: Could not unregister scheduled task '$task_name'" -ForegroundColor Yellow + } + } + } + elseif ($command -eq "uninstall") { + Write-Host "Running in mode: uninstall" -ForegroundColor Yellow + + # Setup uninstall logs + Initialize-Directory $uninstall_logs_dir + New-File $uninstall_log_file + Write-ToLog -message "Starting uninstall process" -log_file $uninstall_log_file + + if (-not (Test-Path -Path $json_uninstall_file_path)) { + $errorMessage = "No uninstall file found at: $json_uninstall_file_path. Please run installer first to create tracking file." + Write-Host $errorMessage -ForegroundColor Red + Write-ToLog -message $errorMessage -log_file $uninstall_log_file + Write-Host "Would you like to create an empty uninstall file to proceed? (y/n)" -ForegroundColor Yellow + $choice = Read-Host + + if ($choice -eq "y") { + try { + # Create directory if it doesn't exist + $uninstallDir = Split-Path -Path $json_uninstall_file_path -Parent + if (-not (Test-Path -Path $uninstallDir)) { + New-Item -Path $uninstallDir -ItemType Directory -Force | Out-Null + Write-Host "Created directory: $uninstallDir" -ForegroundColor Green + } + + # Create empty uninstall JSON file + $emptyJson = @{ + "winget_applications" = @() + "external_applications" = @() + } + $emptyJson | ConvertTo-Json -Depth 4 | Set-Content -Path $json_uninstall_file_path -Force + Write-Host "Created empty uninstall file at: $json_uninstall_file_path" -ForegroundColor Green + Write-ToLog -message "Created empty uninstall file" -log_file $uninstall_log_file + } + catch { + Write-Host "Failed to create uninstall file: $_" -ForegroundColor Red + Write-ToLog -message "Failed to create uninstall file: $_" -log_file $uninstall_log_file + exit 1 + } + } + else { + Write-Host "Uninstall operation cancelled" -ForegroundColor Yellow + exit 0 + } + } + + # Invoke the batch uninstallation process + Invoke-BatchUninstall -json_uninstall_file_path $json_uninstall_file_path -uninstall_log_file $uninstall_log_file + + Write-Host "Uninstallation process completed. Check $uninstall_log_file for details." -ForegroundColor Green + } + else { + $help_str = + @" + Usage: + .\Setup_1.ps1 gui + or + .\Setup_1.ps1 -gui + or + .\Setup_1.ps1 --gui + Shows a Windows Forms interface for interactive package selection and installation/uninstallation + + .\Setup_1.ps1 install + or + .\Setup_1.ps1 -install + or + .\Setup_1.ps1 --install + Installs all software specified in applications.json, checking for dependencies + + .\Setup_1.ps1 uninstall + or + .\Setup_1.ps1 -uninstall + or + .\Setup_1.ps1 --uninstall + Uninstalls all software specified in uninstall.json +"@ + Write-Host $help_str -ForegroundColor Red # Displays usage instructions if the command is invalid + } +} +catch { + Write-ToLog -message $_.Exception.Message -log_file $error_log_file # Logs any exceptions that occur + Write-Host "$($_.Exception.Message)" -ForegroundColor Red # Displays the exception message + Write-Host "An error occurred during installation. See error log files" -ForegroundColor Red # Informs the user of an error + #Write-Host $Error[0].ScriptStackTrace # Optionally displays the script stack trace +} diff --git a/Windows_Software_Installation/WingetGUI_Installer/Setup_2.ps1 b/Windows_Software_Installation/WingetGUI_Installer/Setup_2.ps1 new file mode 100644 index 0000000..3a4a181 --- /dev/null +++ b/Windows_Software_Installation/WingetGUI_Installer/Setup_2.ps1 @@ -0,0 +1,867 @@ +# AI PC Dev Kit Complete Installation Script for Windows + +param( + [string]$DevKitWorkingDir = "C:\Intel", + [int]$MaxRetries = 3 +) + +$ErrorActionPreference = "Stop" + +# Ensure working directory exists +New-Item -ItemType Directory -Path $DevKitWorkingDir -ErrorAction SilentlyContinue +Set-Location $DevKitWorkingDir + +# Function: Download With Progress and Retry +function Start-DownloadWithRetry { + param ( + [string]$Uri, + [string]$OutFile, + [int]$MaxRetries = 3 + ) + + $attempt = 0 + do { + try { + $attempt++ + Write-Host "[Attempt $attempt/$MaxRetries] Downloading $OutFile..." -ForegroundColor Cyan + + $req = [System.Net.HttpWebRequest]::Create($Uri) + $req.Method = "GET" + $res = $req.GetResponse() + $stream = $res.GetResponseStream() + $totalBytes = $res.ContentLength + [byte[]]$buffer = New-Object byte[] 1MB + $bytesRead = 0 + $targetFileStream = [System.IO.File]::Create($OutFile) + + do { + $count = $stream.Read($buffer, 0, $buffer.Length) + $targetFileStream.Write($buffer, 0, $count) + $bytesRead += $count + + if ($totalBytes -gt 0) { + $percentComplete = [Math]::Round(($bytesRead / $totalBytes) * 100, 2) + Write-Progress -Activity "Downloading $OutFile" -Status "$percentComplete% Complete" -PercentComplete $percentComplete + } + } while ($count -gt 0) + + $targetFileStream.Close() + $stream.Close() + Write-Progress -Activity "Downloading $OutFile" -Completed + return $true + } + catch { + Write-Warning "[Attempt $attempt failed] $_" + if ($attempt -lt $MaxRetries) { + $delay = [Math]::Pow(2, $attempt) * 1000 # Exponential backoff: 2s, 4s, 8s... + Write-Host "Retrying in $([Math]::Round($delay / 1000, 1)) seconds..." -ForegroundColor Yellow + Start-Sleep -Milliseconds $delay + } else { + Write-Error "Failed to download $OutFile after $MaxRetries attempts." + return $false + } + } + } while ($attempt -le $MaxRetries) +} + +function Install-PipPackages { + param( + [string]$VenvPath, + [string]$RequirementsFile = $null, + [string[]]$Packages = $null, + [int]$TimeoutSeconds = 300, + [int]$MaxRetries = 3 + ) + + $pipExe = Join-Path $VenvPath "Scripts\pip.exe" + + for ($attempt = 1; $attempt -le $MaxRetries; $attempt++) { + try { + Write-Host "Attempt $attempt of $MaxRetries..." + + if ($RequirementsFile) { + $installArgs = @("install", "-r", $RequirementsFile, "--timeout", $TimeoutSeconds) + } elseif ($Packages) { + $installArgs = @("install") + $Packages + @("--timeout", $TimeoutSeconds) + } + + & $pipExe $installArgs + + if ($LASTEXITCODE -eq 0) { + Write-Host "Package installation successful" -ForegroundColor Green + return $true + } else { + Write-Host "Package installation failed (attempt $attempt)" -ForegroundColor Yellow + } + } + catch { + Write-Host "Exception during package installation (attempt $attempt): $_" -ForegroundColor Yellow + } + + if ($attempt -lt $MaxRetries) { + Write-Host "Retrying in 5 seconds..." -ForegroundColor Yellow + Start-Sleep -Seconds 5 + } + } + + Write-Host "Trying with alternative PyPI mirror..." -ForegroundColor Yellow + try { + if ($RequirementsFile) { + $installArgs = @("install", "-r", $RequirementsFile, "--timeout", $TimeoutSeconds, "-i", "https://pypi.org/simple/") + } elseif ($Packages) { + $installArgs = @("install") + $Packages + @("--timeout", $TimeoutSeconds, "-i", "https://pypi.org/simple/") + } + + & $pipExe $installArgs + + if ($LASTEXITCODE -eq 0) { + Write-Host "Package installation successful with alternative mirror" -ForegroundColor Green + return $true + } + } + catch { + Write-Host "Exception with alternative mirror: $_" -ForegroundColor Yellow + } + + Write-Host "Failed to install packages after all attempts" -ForegroundColor Red + return $false +} + +function New-PythonVenv { + param( + [string]$Path, + [string]$VenvName = "venv" + ) + + $venvPath = Join-Path $Path $VenvName + + if (Test-Path $venvPath) { + Write-Host "Virtual environment already exists at: $venvPath" -ForegroundColor Yellow + return $venvPath + } + + try { + Write-Host "Creating Python virtual environment at: $venvPath" + & python -m venv $venvPath + + if ($LASTEXITCODE -eq 0) { + Write-Host "Virtual environment created successfully" -ForegroundColor Green + return $venvPath + } else { + Write-Host "Failed to create virtual environment" -ForegroundColor Red + return $null + } + } + catch { + Write-Host "Exception creating virtual environment: $_" -ForegroundColor Red + return $null + } +} + +function Test-PyPIConnectivity { + try { + Write-Host "Checking network connectivity to PyPI..." + $response = Invoke-WebRequest -Uri "https://pypi.org" -Method Head -TimeoutSec 10 -ErrorAction Stop + if ($response.StatusCode -eq 200) { + Write-Host "Network connectivity to PyPI is working" -ForegroundColor Green + return $true + } + } + catch { + Write-Host "Warning: Network connectivity to PyPI seems slow or unavailable" -ForegroundColor Yellow + return $false + } +} + +function Test-BuildEnvironment { + $vcvarsFound = $false + $cmakeFound = $false + $cmakeVersionOk = $false + + # Check for CMake and version + try { + $cmakeOutput = & cmake --version 2>$null + if ($LASTEXITCODE -eq 0 -and $cmakeOutput) { + $cmakeFound = $true + # Extract version number from output like "cmake version 3.XX.X" or "cmake version 4.XX.X" + if ($cmakeOutput[0] -match "cmake version (\d+)\.(\d+)\.(\d+)") { + $majorVersion = [int]$matches[1] + $minorVersion = [int]$matches[2] + if ($majorVersion -gt 3 -or ($majorVersion -eq 3 -and $minorVersion -ge 5)) { + $cmakeVersionOk = $true + Write-Host "CMake version OK: $($cmakeOutput[0])" -ForegroundColor Green + } else { + Write-Host "CMake version too old: $($cmakeOutput[0]) (requires 3.5+)" -ForegroundColor Yellow + } + } + } + } + catch { + Write-Host "CMake not found in PATH" -ForegroundColor Yellow + } + + # Check for Visual Studio Build Tools (look for common vcvarsall.bat locations) + $vcvarsPaths = @( + "${env:ProgramFiles}\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvarsall.bat", + "${env:ProgramFiles}\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat", + "${env:ProgramFiles}\Microsoft Visual Studio\2022\Professional\VC\Auxiliary\Build\vcvarsall.bat", + "${env:ProgramFiles}\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat", + "${env:ProgramFiles(x86)}\Microsoft Visual Studio\2019\BuildTools\VC\Auxiliary\Build\vcvarsall.bat", + "${env:ProgramFiles(x86)}\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" + ) + + foreach ($vcvarsPath in $vcvarsPaths) { + if (Test-Path $vcvarsPath) { + $vcvarsFound = $true + Write-Host "Visual Studio Build Tools found at: $vcvarsPath" -ForegroundColor Green + break + } + } + + if (-not $vcvarsFound) { + Write-Host "Visual Studio Build Tools not found" -ForegroundColor Yellow + } + + if (-not $cmakeFound) { + Write-Host "CMake not found" -ForegroundColor Yellow + } elseif (-not $cmakeVersionOk) { + Write-Host "CMake version incompatible (needs 3.5+)" -ForegroundColor Yellow + } + + return ($vcvarsFound -and $cmakeFound -and $cmakeVersionOk) +} + +function Install-JupyterKernel { + param( + [string]$VenvPath, + [string]$KernelName, + [string]$DisplayName + ) + + Write-Host "Installing ipykernel and creating Jupyter kernel..." -ForegroundColor Cyan + $ipykernelSuccess = Install-PipPackages -VenvPath $VenvPath -Packages @("ipykernel") + if ($ipykernelSuccess) { + $pythonExe = Join-Path $VenvPath "Scripts\python.exe" + try { + & $pythonExe -m ipykernel install --user --name=$KernelName --display-name="$DisplayName" + Write-Host "Jupyter kernel '$KernelName' created successfully" -ForegroundColor Green + } + catch { + Write-Host "Failed to create Jupyter kernel: $_" -ForegroundColor Yellow + } + } +} + +# Main Installation Process +Write-Host "Starting AI PC Dev Kit Complete Installation..." -ForegroundColor Cyan +Test-PyPIConnectivity + +# Step 1: Fast Parallel Downloads +Write-Host "`n=== STEP 1: DOWNLOADING REPOSITORIES ===" -ForegroundColor Magenta + +# Setup Runspace Pool for Parallel Downloads +$runspacePool = [runspacefactory]::CreateRunspacePool(1, 5) +$runspacePool.Open() + +$jobs = @() + +# Define Repos +$repos = @( + @{ Name = "openvino_notebooks"; Uri = "https://github.com/openvinotoolkit/openvino_notebooks/archive/refs/heads/2025.3.zip"; File = "2025.3.zip" }, + @{ Name = "openvino_build_deploy"; Uri = "https://github.com/openvinotoolkit/openvino_build_deploy/archive/refs/heads/master.zip"; File = "master-build_deploy.zip" }, + @{ Name = "ollama-ipex-llm"; Uri = "https://github.com/ipex-llm/ipex-llm/releases/download/v2.3.0-nightly/ollama-ipex-llm-2.3.0b20250725-win.zip"; File = "ollama-ipex-llm.zip" }, + @{ Name = "openvino_genai"; Uri = "https://storage.openvinotoolkit.org/repositories/openvino_genai/packages/2025.3/windows/openvino_genai_windows_2025.3.0.0_x86_64.zip"; File = "openvino_genai.zip" }, + @{ Name = "AI-PC-Samples"; Uri = "https://github.com/intel/AI-PC-Samples/archive/refs/heads/main.zip"; File = "ai-pc-samples.zip" }, + @{ Name = "open_model_zoo"; Uri = "https://github.com/openvinotoolkit/open_model_zoo/archive/refs/tags/2024.4.0.zip"; File = "2024.4.0.zip" } +) + +# Launch jobs +$skipped = 0 +foreach ($repo in $repos) { + # Check if target directory already exists - skip download if so + if (Test-Path $repo.Name) { + Write-Host "SKIP: $($repo.Name) directory already exists, skipping download." -ForegroundColor Yellow + $skipped++ + continue + } + + # Check if zip file already exists - skip download if so + $zipPath = Join-Path $DevKitWorkingDir $repo.File + if (Test-Path $zipPath) { + Write-Host "SKIP: $($repo.File) already downloaded." -ForegroundColor Yellow + $skipped++ + continue + } + + $scriptBlock = { + param($Uri, $OutFile, $Name, $MaxRetries, $WorkingDir) + + function Start-DownloadWithRetry { + param ($Uri, $OutFile, [int]$MaxRetries = 3) + $attempt = 0 + $fullPath = Join-Path $WorkingDir $OutFile + do { + try { + $attempt++ + Write-Host "[Attempt $attempt/$MaxRetries] $Name..." -ForegroundColor Gray + $req = [System.Net.HttpWebRequest]::Create($Uri) + $req.Method = "GET" + $res = $req.GetResponse() + $stream = $res.GetResponseStream() + $totalBytes = $res.ContentLength + [byte[]]$buffer = New-Object byte[] 1MB + $bytesRead = 0 + $targetFileStream = [System.IO.File]::Create($fullPath) + + do { + $count = $stream.Read($buffer, 0, $buffer.Length) + $targetFileStream.Write($buffer, 0, $count) + $bytesRead += $count + + if ($totalBytes -gt 0) { + $percentComplete = [Math]::Round(($bytesRead / $totalBytes) * 100, 2) + # Progress doesn't show in runspaces, so we'll log instead + if ($bytesRead % (5 * 1MB) -eq 0 -or $count -eq 0) { + Write-Host "[$Name] $percentComplete% downloaded" -ForegroundColor Gray + } + } + } while ($count -gt 0) + + $targetFileStream.Close() + $stream.Close() + Write-Host "[$Name] Download completed!" -ForegroundColor Green + return $true + } + catch { + Write-Warning "[${Name}] Attempt $attempt failed: $_" + if ($attempt -lt $MaxRetries) { + $delay = [Math]::Pow(2, $attempt) * 1000 + Start-Sleep -Milliseconds $delay + } else { + return $false + } + } + } while ($attempt -le $MaxRetries) + } + + Start-DownloadWithRetry -Uri $Uri -OutFile $OutFile -MaxRetries $MaxRetries + } + + $powershell = [powershell]::Create(). + AddScript($scriptBlock). + AddArgument($repo.Uri). + AddArgument($repo.File). + AddArgument($repo.Name). + AddArgument($MaxRetries). + AddArgument($DevKitWorkingDir) + + $powershell.RunspacePool = $runspacePool + $handle = $powershell.BeginInvoke() + $jobs += [PSCustomObject]@{ + Name = $repo.Name + Job = $powershell + Handle = $handle + File = $repo.File + } +} + +# Wait for all downloads +if ($jobs.Count -eq 0) { + Write-Host "`nNo downloads needed - all repositories already exist or are downloaded." -ForegroundColor Green +} else { + Write-Host "`nWaiting for $($jobs.Count) downloads to complete... ($skipped skipped)" -ForegroundColor Yellow + $completed = 0 + $total = $jobs.Count + Write-Host "Downloads completed: $completed/$total" -ForegroundColor Cyan + + while ($completed -lt $total) { + Start-Sleep -Milliseconds 500 # Check more frequently + $newCompleted = ($jobs | Where-Object { $_.Handle.IsCompleted }).Count + if ($newCompleted -gt $completed) { + $completed = $newCompleted + Write-Host "Downloads completed: $completed/$total" -ForegroundColor Cyan + } + } +} + +# Check Results +$downloadResults = foreach ($job in $jobs) { + try { + $result = $job.Job.EndInvoke($job.Handle) + [PSCustomObject]@{ + Name = $job.Name + Success = $result + File = $job.File + } + } catch { + [PSCustomObject]@{ + Name = $job.Name + Success = $false + File = $job.File + } + } finally { + $job.Job.Dispose() + } +} + +# Extract archives - FIXED DIRECTORY NAMES +foreach ($result in $downloadResults) { + if (-not $result.Success) { + Write-Error "Skipping extraction for $($result.Name) due to download failure." + continue + } + + $name = $result.Name + $file = $result.File + + if (Test-Path $name) { + Write-Host "SKIP: $name already exists." -ForegroundColor Yellow + continue + } + + Write-Host "`nExtracting $file -> $name..." -ForegroundColor Cyan + try { + Expand-Archive -Path "$DevKitWorkingDir\$file" -DestinationPath $DevKitWorkingDir -Force + Remove-Item "$DevKitWorkingDir\$file" -Force + + switch ($name) { + "openvino_notebooks" { + # FIXED: Updated from 2025.2 to 2025.3 + if (Test-Path "openvino_notebooks-2025.3") { + Rename-Item "openvino_notebooks-2025.3" $name + } + } + "openvino_build_deploy" { + if (Test-Path "openvino_build_deploy-master") { + Rename-Item "openvino_build_deploy-master" $name + } + } + "webnn_workshop" { + if (Test-Path "webnn_workshop-main") { + Rename-Item "webnn_workshop-main" $name + } + } + "AI-PC-Samples" { + if (Test-Path "AI-PC-Samples-main") { + Rename-Item "AI-PC-Samples-main" $name + } + } + "openvino_genai" { + # FIXED: Updated from 2025.2.0.0 to 2025.3.0.0 + if (Test-Path "openvino_genai_windows_2025.3.0.0_x86_64") { + Rename-Item "openvino_genai_windows_2025.3.0.0_x86_64" $name + } + } + "ollama-ipex-llm" { + # This ZIP extracts files directly to the current directory, not into a subdirectory + # We need to create the target directory and move the files there + Write-Host "Creating $name directory and moving extracted files..." -ForegroundColor Magenta + + # Get a list of all files that were likely extracted from this ZIP + $ollamaFiles = Get-ChildItem -Path $DevKitWorkingDir -File | Where-Object { + $_.Name -like "*ollama*" -or + $_.Name -like "*llama*" -or + $_.Name -like "*.dll" -or + $_.Name -like "*.exe" -or + $_.Name -like "*.bat" -or + $_.Name -like "*.txt" + } + + if ($ollamaFiles.Count -gt 0) { + # Create the target directory + New-Item -ItemType Directory -Path $name -Force | Out-Null + + # Move all the extracted files to the new directory + foreach ($file in $ollamaFiles) { + Move-Item -Path $file.FullName -Destination $name -Force + } + + Write-Host "Moved $($ollamaFiles.Count) files to $name directory" -ForegroundColor Magenta + } else { + Write-Host "No ollama/llama files found to move" -ForegroundColor Yellow + } + } + "open_model_zoo" { + if (Test-Path "open_model_zoo-2024.4.0") { + Rename-Item "open_model_zoo-2024.4.0" $name + } + } + Default {} + } + Write-Host "SUCCESS: $name ready." -ForegroundColor Green + } catch { + Write-Error "Failed to extract $file`: $_" + } +} + +$runspacePool.Close() +$runspacePool.Dispose() + +# Step 2: Setup Virtual Environments and Install Dependencies +Write-Host "`n=== STEP 2: SETTING UP VIRTUAL ENVIRONMENTS ===" -ForegroundColor Magenta + +# 1. OpenVINO Notebooks +if (Test-Path "openvino_notebooks") { + Write-Host "`nSetting up OpenVINO Notebooks environment..." -ForegroundColor Cyan + $venvPath = New-PythonVenv -Path "$DevKitWorkingDir\openvino_notebooks" + if ($venvPath) { + $requirementsPath = Join-Path "$DevKitWorkingDir\openvino_notebooks" "requirements.txt" + if (Test-Path $requirementsPath) { + Write-Host "Installing OpenVINO notebooks requirements..." + $success = Install-PipPackages -VenvPath $venvPath -RequirementsFile $requirementsPath + if ($success) { + Install-JupyterKernel -VenvPath $venvPath -KernelName "openvino_notebooks" -DisplayName "OpenVINO Notebooks" + } else { + Write-Host "Manual command: cd `"$DevKitWorkingDir\openvino_notebooks`"; .\venv\Scripts\activate; pip install -r requirements.txt" -ForegroundColor Yellow + } + } + } +} + +# 2. OpenVINO Build Deploy (MSBuild2025 Workshop) +if (Test-Path "openvino_build_deploy") { + Write-Host "`nSetting up MSBuild2025 Workshop environment..." -ForegroundColor Cyan + $workshopPath = "$DevKitWorkingDir\openvino_build_deploy\workshops\MSBuild2025" + if (Test-Path $workshopPath) { + $venvPath = New-PythonVenv -Path $workshopPath + if ($venvPath) { + Write-Host "Installing OpenVINO and Ultralytics packages..." + # UPDATED: Changed from 2025.1.0 to 2025.3.0 to match the current version + $packages = @("openvino==2025.3.0", "ultralytics==8.3.120") + $success = Install-PipPackages -VenvPath $venvPath -Packages $packages + if ($success) { + Install-JupyterKernel -VenvPath $venvPath -KernelName "msbuild2025_workshop" -DisplayName "MSBuild2025 Workshop" + } else { + Write-Host "Manual command: cd `"$workshopPath`"; .\venv\Scripts\activate; pip install openvino==2025.3.0 ultralytics==8.3.120" -ForegroundColor Yellow + } + } + } +} + +# 3. OpenVINO GenAI +if (Test-Path "openvino_genai") { + Write-Host "`nSetting up OpenVINO GenAI environment..." -ForegroundColor Cyan + $genaiPath = "$DevKitWorkingDir\openvino_genai" + Set-Location $genaiPath + + Write-Host "Using pre-built binary package" -ForegroundColor Green + # Install OpenVINO dependencies (Windows equivalent) + $dependenciesScript = Join-Path $genaiPath "install_dependencies\install_openvino_dependencies.ps1" + if (Test-Path $dependenciesScript) { + Write-Host "Installing OpenVINO dependencies..." -ForegroundColor Cyan + try { + & $dependenciesScript + Write-Host "Dependencies installed successfully" -ForegroundColor Green + } + catch { + Write-Host "Warning: Failed to install dependencies: $_" -ForegroundColor Yellow + } + } + + # Source setupvars.ps1 (Windows equivalent of setupvars.sh) + $setupvarsScript = Join-Path $genaiPath "setupvars.ps1" + if (Test-Path $setupvarsScript) { + Write-Host "Sourcing setupvars.ps1..." -ForegroundColor Cyan + try { + & $setupvarsScript + Write-Host "Environment variables set successfully" -ForegroundColor Green + } + catch { + Write-Host "Warning: Failed to source setupvars.ps1: $_" -ForegroundColor Yellow + } + } + + # Test build environment and attempt to build C++ samples + $cppSamplesPath = Join-Path $genaiPath "samples\cpp" + if (Test-Path $cppSamplesPath) { + # Ensure we're in the correct directory for building + Push-Location $cppSamplesPath + + if (Test-BuildEnvironment) { + $buildScript = Join-Path $cppSamplesPath "build_samples.ps1" + if (Test-Path $buildScript) { + Write-Host "Building C++ samples in: $cppSamplesPath" -ForegroundColor Cyan + try { + # Use CMAKE_POLICY_VERSION_MINIMUM for CMake 4.0 compatibility + $env:CMAKE_POLICY_VERSION_MINIMUM = "3.5" + + Write-Host "Using CMAKE_POLICY_VERSION_MINIMUM=3.5 for CMake 4.0 compatibility..." -ForegroundColor Yellow + + # Try the build with the policy version minimum + & $buildScript + + if ($LASTEXITCODE -eq 0) { + Write-Host "C++ samples built successfully" -ForegroundColor Green + } else { + Write-Host "Build completed with warnings/errors (exit code: $LASTEXITCODE)" -ForegroundColor Yellow + Write-Host "This is common with OpenVINO GenAI samples and may not prevent usage" -ForegroundColor Yellow + } + } + catch { + Write-Host "Build script execution failed: $_" -ForegroundColor Yellow + Write-Host "Attempting direct CMake build..." -ForegroundColor Yellow + + # Try direct cmake approach with CMAKE_POLICY_VERSION_MINIMUM + try { + Write-Host "Trying direct CMake build with policy version minimum..." -ForegroundColor Cyan + $buildDir = Join-Path $cppSamplesPath "build" + if (-not (Test-Path $buildDir)) { + New-Item -ItemType Directory -Path $buildDir -Force | Out-Null + } + Push-Location $buildDir + + # Configure with CMAKE_POLICY_VERSION_MINIMUM + & cmake .. -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -DCMAKE_BUILD_TYPE=Release + if ($LASTEXITCODE -eq 0) { + & cmake --build . --config Release + if ($LASTEXITCODE -eq 0) { + Write-Host "Direct CMake build succeeded" -ForegroundColor Green + } else { + Write-Host "Direct CMake build completed with warnings" -ForegroundColor Yellow + } + } + Pop-Location + } + catch { + Write-Host "Direct CMake approach also failed: $_" -ForegroundColor Yellow + # Ensure we return to the correct location even on error + try { Pop-Location } catch { } + } + } + finally { + # Clean up environment variable + Remove-Item env:CMAKE_POLICY_VERSION_MINIMUM -ErrorAction SilentlyContinue + } + } else { + Write-Host "Warning: build_samples.ps1 not found at $buildScript" -ForegroundColor Yellow + } + } else { + Write-Host "Warning: Build environment not properly configured. Skipping C++ samples build." -ForegroundColor Yellow + Write-Host "Requirements for C++ sample compilation:" -ForegroundColor Yellow + Write-Host "1. Install Visual Studio Build Tools 2022 or Visual Studio Community 2022" -ForegroundColor White + Write-Host "2. Install CMake 3.5+ and add to PATH" -ForegroundColor White + Write-Host "3. Run: cd `"$cppSamplesPath`"; .\build_samples.ps1" -ForegroundColor White + Write-Host "Alternative: Use pre-built Python samples instead" -ForegroundColor White + } + + # Return to the original location + Pop-Location + } + + # Return to base directory and setup Python environment + Set-Location $DevKitWorkingDir + $samplesPath = "$DevKitWorkingDir\openvino_genai\samples" + if (Test-Path $samplesPath) { + $venvPath = New-PythonVenv -Path $samplesPath + if ($venvPath) { + $requirementsPath = Join-Path $samplesPath "requirements.txt" + if (Test-Path $requirementsPath) { + Write-Host "Installing OpenVINO GenAI requirements..." -ForegroundColor Cyan + $success = Install-PipPackages -VenvPath $venvPath -RequirementsFile $requirementsPath + if ($success) { + Install-JupyterKernel -VenvPath $venvPath -KernelName "openvino_genai" -DisplayName "OpenVINO GenAI" + } else { + Write-Host "Manual command: cd `"$samplesPath`"; .\venv\Scripts\activate; pip install -r requirements.txt" -ForegroundColor Yellow + } + } + } + } +} + +# 4. AI-PC-Samples (Intel AI PC Samples) +if (Test-Path "AI-PC-Samples") { + Write-Host "`nSetting up AI PC Samples environment..." -ForegroundColor Cyan + $venvPath = New-PythonVenv -Path "$DevKitWorkingDir\AI-PC-Samples" + if ($venvPath) { + # Check for requirements.txt in AI-Travel-Agent subdirectory first + $requirementsPath = Join-Path "$DevKitWorkingDir\AI-PC-Samples\AI-Travel-Agent" "requirements.txt" + if (-not (Test-Path $requirementsPath)) { + # Fallback to root directory requirements.txt + $requirementsPath = Join-Path "$DevKitWorkingDir\AI-PC-Samples" "requirements.txt" + } + + if (Test-Path $requirementsPath) { + Write-Host "Installing AI PC Samples requirements..." + $success = Install-PipPackages -VenvPath $venvPath -RequirementsFile $requirementsPath + if ($success) { + Install-JupyterKernel -VenvPath $venvPath -KernelName "ai_pc_samples" -DisplayName "AI PC Samples" + + # Install LlamaCpp Python with Vulkan support + Write-Host "Installing LlamaCpp Python with Vulkan support..." -ForegroundColor Cyan + $pipExe = Join-Path $venvPath "Scripts\pip.exe" + try { + # Set environment variables for Vulkan compilation + $env:CMAKE_ARGS = "-DGGML_VULKAN=on" + $env:FORCE_CMAKE = "1" + + Write-Host "Compiling llama-cpp-python with Vulkan support (this may take several minutes)..." -ForegroundColor Yellow + & $pipExe install llama-cpp-python==0.3.8 -U --force --no-cache-dir --verbose + + if ($LASTEXITCODE -eq 0) { + Write-Host "LlamaCpp Python with Vulkan compiled successfully!" -ForegroundColor Green + } else { + Write-Host "LlamaCpp Python compilation failed, continuing with standard installation..." -ForegroundColor Yellow + } + } + catch { + Write-Host "Exception during LlamaCpp Python compilation: $_" -ForegroundColor Yellow + } + finally { + # Clean up environment variables + Remove-Item env:CMAKE_ARGS -ErrorAction SilentlyContinue + Remove-Item env:FORCE_CMAKE -ErrorAction SilentlyContinue + } + + + } else { + Write-Host "Manual command: cd `"$DevKitWorkingDir\AI-PC-Samples`"; .\venv\Scripts\activate; pip install -r AI-Travel-Agent\requirements.txt" -ForegroundColor Yellow + } + } else { + # If no requirements.txt, install basic packages for AI PC Samples + Write-Host "Installing basic packages for AI PC Samples..." + $packages = @("numpy", "matplotlib", "jupyter", "ipywidgets", "torch", "transformers", "opencv-python") + $success = Install-PipPackages -VenvPath $venvPath -Packages $packages + if ($success) { + Install-JupyterKernel -VenvPath $venvPath -KernelName "ai_pc_samples" -DisplayName "AI PC Samples" + + # Install LlamaCpp Python with Vulkan support (same as above) + Write-Host "Installing LlamaCpp Python with Vulkan support..." -ForegroundColor Cyan + $pipExe = Join-Path $venvPath "Scripts\pip.exe" + try { + # Set environment variables for Vulkan compilation + $env:CMAKE_ARGS = "-DGGML_VULKAN=on" + $env:FORCE_CMAKE = "1" + + Write-Host "Compiling llama-cpp-python with Vulkan support (this may take several minutes)..." -ForegroundColor Yellow + & $pipExe install llama-cpp-python==0.3.8 -U --force --no-cache-dir --verbose + + if ($LASTEXITCODE -eq 0) { + Write-Host "LlamaCpp Python with Vulkan compiled successfully!" -ForegroundColor Green + } else { + Write-Host "LlamaCpp Python compilation failed, continuing..." -ForegroundColor Yellow + } + } + catch { + Write-Host "Exception during LlamaCpp Python compilation: $_" -ForegroundColor Yellow + } + finally { + # Clean up environment variables + Remove-Item env:CMAKE_ARGS -ErrorAction SilentlyContinue + Remove-Item env:FORCE_CMAKE -ErrorAction SilentlyContinue + } + } + } + } +} + +# 5. LlamaCpp with Vulkan (Independent Installation) +Write-Host "`nSetting up LlamaCpp with Vulkan in C:\Intel..." -ForegroundColor Cyan +$llamacppPath = Join-Path $DevKitWorkingDir "llama.cpp" +if (-not (Test-Path $llamacppPath)) { + Set-Location $DevKitWorkingDir + + try { + Write-Host "Cloning LlamaCpp repository to C:\Intel\llama.cpp..." -ForegroundColor Cyan + & git clone https://github.com/ggml-org/llama.cpp.git + + if (Test-Path $llamacppPath) { + Set-Location $llamacppPath + + if (Test-BuildEnvironment) { + Write-Host "Building native LlamaCpp with Vulkan support in: $llamacppPath" -ForegroundColor Cyan + + # Configure with CMake + & cmake -B build -DGGML_VULKAN=ON -DLLAMA_CURL=OFF + + if ($LASTEXITCODE -eq 0) { + Write-Host "CMake configuration successful, building..." -ForegroundColor Green + & cmake --build build --config Release -j + + if ($LASTEXITCODE -eq 0) { + Write-Host "Native LlamaCpp built successfully in: $llamacppPath" -ForegroundColor Green + } else { + Write-Host "Native LlamaCpp build completed with warnings" -ForegroundColor Yellow + } + } else { + Write-Host "CMake configuration failed for native LlamaCpp" -ForegroundColor Yellow + } + } else { + Write-Host "Build environment not available, skipping native LlamaCpp compilation" -ForegroundColor Yellow + Write-Host "Requirements: Visual Studio Build Tools 2022 + CMake 3.5+" -ForegroundColor White + } + } + } + catch { + Write-Host "Failed to clone or build native LlamaCpp: $_" -ForegroundColor Yellow + } + finally { + Set-Location $DevKitWorkingDir + } +} else { + Write-Host "Native LlamaCpp already exists at: $llamacppPath, skipping..." -ForegroundColor Yellow +} + +# 6. Open Model Zoo +if (Test-Path "open_model_zoo") { + Write-Host "`nSetting up Open Model Zoo environment..." -ForegroundColor Cyan + $venvPath = New-PythonVenv -Path "$DevKitWorkingDir\open_model_zoo" + if ($venvPath) { + $requirementsPath = Join-Path "$DevKitWorkingDir\open_model_zoo" "requirements.txt" + if (Test-Path $requirementsPath) { + Write-Host "Installing Open Model Zoo requirements..." + $success = Install-PipPackages -VenvPath $venvPath -RequirementsFile $requirementsPath + if ($success) { + Install-JupyterKernel -VenvPath $venvPath -KernelName "open_model_zoo" -DisplayName "Open Model Zoo" + } else { + Write-Host "Manual command: cd `"$DevKitWorkingDir\open_model_zoo`"; .\venv\Scripts\activate; pip install -r requirements.txt" -ForegroundColor Yellow + } + } else { + # If no requirements.txt, install basic OpenVINO packages + Write-Host "Installing basic packages for Open Model Zoo..." + $packages = @("openvino", "opencv-python", "numpy", "matplotlib", "jupyter", "ipywidgets") + $success = Install-PipPackages -VenvPath $venvPath -Packages $packages + if ($success) { + Install-JupyterKernel -VenvPath $venvPath -KernelName "open_model_zoo" -DisplayName "Open Model Zoo" + } + } + } +} + +# Clean up any remaining zip files - UPDATED ZIP FILE NAMES +Write-Host "`nCleaning up downloaded zip files..." -ForegroundColor Cyan +$zipFiles = @("2025.3.zip", "master-build_deploy.zip", "ollama-ipex-llm.zip", "openvino_genai.zip", "ai-pc-samples.zip", "2024.4.0.zip") +foreach ($zipFile in $zipFiles) { + if (Test-Path $zipFile) { + Remove-Item $zipFile -Force + Write-Host "Removed: $zipFile" + } +} + +# Final Summary +Write-Host "`n=== INSTALLATION SUMMARY ===" -ForegroundColor Magenta +Write-Host "AI PC DevKit Complete Installation finished!" -ForegroundColor Green +Write-Host "Installation directory: $DevKitWorkingDir" -ForegroundColor Green + +Write-Host "`nJupyter Kernels Created:" -ForegroundColor Yellow +Write-Host "- openvino_notebooks (OpenVINO Notebooks)" -ForegroundColor White +Write-Host "- msbuild2025_workshop (MSBuild2025 Workshop)" -ForegroundColor White +Write-Host "- openvino_genai (OpenVINO GenAI)" -ForegroundColor White +Write-Host "- ai_pc_samples (AI PC Samples)" -ForegroundColor White +Write-Host "- open_model_zoo (Open Model Zoo)" -ForegroundColor White + +Write-Host "`nTo use Jupyter kernels:" -ForegroundColor Yellow +Write-Host "1. Start Jupyter: jupyter lab" -ForegroundColor White +Write-Host "2. Select kernel from the dropdown menu when creating/opening notebooks" -ForegroundColor White + +Write-Host "`nTo activate virtual environments:" -ForegroundColor Yellow +Write-Host "OpenVINO Notebooks: cd `"$DevKitWorkingDir\openvino_notebooks`"; .\venv\Scripts\activate" -ForegroundColor White +Write-Host "MSBuild2025 Workshop: cd `"$DevKitWorkingDir\openvino_build_deploy\workshops\MSBuild2025`"; .\venv\Scripts\activate" -ForegroundColor White +Write-Host "OpenVINO GenAI: cd `"$DevKitWorkingDir\openvino_genai\samples`"; .\venv\Scripts\activate" -ForegroundColor White +Write-Host "AI PC Samples: cd `"$DevKitWorkingDir\AI-PC-Samples`"; .\venv\Scripts\activate" -ForegroundColor White +Write-Host "Open Model Zoo: cd `"$DevKitWorkingDir\open_model_zoo`"; .\venv\Scripts\activate" -ForegroundColor White + +Write-Host "`nNative Tools Built:" -ForegroundColor Yellow +Write-Host "LlamaCpp with Vulkan: $DevKitWorkingDir\llama.cpp\build" -ForegroundColor White +Write-Host "OpenVINO GenAI C++ Samples: $DevKitWorkingDir\openvino_genai\samples\cpp\build" -ForegroundColor White + +Write-Host "`nScript completed successfully!" -ForegroundColor Green