├── Windows_Software_Installation ├── WingetGUI_Installer │ ├── Public │ │ ├── Write_ToLog.ps1 │ │ ├── Run_Once_Eula.ps1 │ │ ├── Pre_Req.ps1 │ │ ├── Install.ps1 │ │ ├── Append-ToJson.ps1 │ │ └── Uninstall.ps1 │ └── JSON │ │ └── install │ │ └── applications.json ├── OVMS │ ├── README_OVMS.md │ └── ovms_setup.ps1 └── README.md ├── .gitignore ├── .github ├── actions │ ├── envsetup │ │ ├── action.yml │ │ └── README.md │ ├── buildartifact │ │ ├── action.yml │ │ └── README.md │ ├── scans │ │ ├── bandit │ │ │ ├── action.yml │ │ │ └── README.md │ │ ├── trivy │ │ │ ├── action.yml │ │ │ └── README.md │ │ ├── clamav │ │ │ ├── action.yml │ │ │ └── README.md │ │ └── coverity │ │ │ ├── action.yml │ │ │ └── README.md │ └── linting │ │ ├── action.yml │ │ └── README.md └── workflows │ └── build.yml ├── LICENSE ├── Linux_Software_Installation ├── Utilities │ ├── compatibility_check_README.md │ ├── verify_connectivity.sh │ └── compatibility_check.sh ├── setup-software.sh └── README.md └── README.md /Windows_Software_Installation/WingetGUI_Installer/Public/Write_ToLog.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | Helper function to just write to any given log, with timestamp included 3 | Creates file if it does not exist already 4 | #> 5 | function Write-ToLog { 6 | param ( 7 | [string]$message, 8 | [string]$log_file 9 | ) 10 | $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" 11 | # Create file if it doesn't exist 12 | if (-not (Test-Path -Path $log_file)) { 13 | New-Item -Path $log_file -ItemType File 14 | } 15 | "$timestamp - $message" | Out-File -FilePath $log_file -Append 16 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated files 2 | setup-static-drivers.sh 3 | 4 | # IDE and editor directories 5 | .vscode/ 6 | .idea/ 7 | *.swp 8 | *.swo 9 | *~ 10 | 11 | # OS generated files 12 | .DS_Store 13 | .DS_Store? 14 | ._* 15 | .Spotlight-V100 16 | .Trashes 17 | ehthumbs.db 18 | Thumbs.db 19 | 20 | # Temporary files 21 | *.tmp 22 | *.temp 23 | /tmp/ 24 | temp/ 25 | 26 | # Log files 27 | *.log 28 | logs/ 29 | error.txt 30 | 31 | # Installer-specific generated files (winget_installer) 32 | SetupScript/EnvSetup/logs/ 33 | SetupScript/EnvSetup/json/uninstall/ 34 | **/install_log.txt 35 | **/error_log.txt 36 | **/uninstall.txt 37 | **/uninstall.json 38 | 39 | # Package files 40 | *.deb 41 | *.ddeb 42 | *.rpm 43 | *.tar.gz 44 | *.zip 45 | 46 | # Backup files 47 | *.bak 48 | *.backup 49 | *~ 50 | -------------------------------------------------------------------------------- /.github/actions/envsetup/action.yml: -------------------------------------------------------------------------------- 1 | name: Setup Python and Package 2 | description: This action sets up Python and installs necessary packages. 3 | inputs: 4 | python-version: 5 | description: 'Python version to use' 6 | required: false 7 | default: '3.10.11' 8 | 9 | permissions: read-all # Adding Permission as Read for all of the available permissions 10 | 11 | runs: 12 | using: "composite" 13 | steps: 14 | - name: Set up Python 15 | uses: actions/setup-python@v4 16 | with: 17 | python-version: '3.10.11' 18 | 19 | - name: Verify Python in PATH and Install dependencies 20 | run: | 21 | python --version 22 | python -m pip install --upgrade pip 23 | python -m pip install pyinstaller 24 | python -m pip install pyinstaller-versionfile 25 | shell: pwsh 26 | 27 | - name: Verify PyInstaller Installation 28 | run: | 29 | python --version 30 | pyinstaller --version 31 | shell: pwsh -------------------------------------------------------------------------------- /.github/actions/buildartifact/action.yml: -------------------------------------------------------------------------------- 1 | name: Build The Project 2 | description: This action builds the project and uploads it to the Artifactory. 3 | inputs: 4 | upload_to_artifactory: 5 | description: 'Flag to control whether to upload to Artifactory' 6 | required: false 7 | default: 'false' 8 | 9 | permissions: read-all 10 | # Adding read permissions for all available permissions 11 | 12 | runs: 13 | using: "composite" 14 | steps: 15 | - name: Run Build 16 | run: | 17 | cd build 18 | .\Build.bat 19 | shell: pwsh 20 | 21 | - name: Prepare files for upload 22 | run: | 23 | mkdir -p upload 24 | cp dist/* upload/ 25 | cp -r AIDevKit upload/ 26 | cp CHANGELOG.md upload/ 27 | cp License.txt upload/ 28 | cp Installation_Guide.md upload/README.md 29 | shell: pwsh 30 | 31 | - name: Upload binary as artifact 32 | if: ${{ inputs.upload_to_artifactory == 'true' }} 33 | uses: actions/upload-artifact@v4 34 | with: 35 | name: ArtifactAIPC 36 | path: upload/ 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Intel 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/actions/scans/bandit/action.yml: -------------------------------------------------------------------------------- 1 | 2 | name: 'Bandit Actions Scan' 3 | description: 'Perform security scanning using Bandit' 4 | inputs: 5 | # Bandit specific inputs 6 | report_name: 7 | description: 'Name of the report file' 8 | required: false 9 | default: 'bandit-results' 10 | upload_to_artifactory: 11 | description: 'Flag to control whether to upload to Artifactory' 12 | required: false 13 | default: 'false' 14 | run_bandit_scan: 15 | description: 'run bandit scan and also upload to artifactory' 16 | required: false 17 | default: 'false' 18 | 19 | permissions: read-all 20 | #Adding Permission as Read for all of the available permissions 21 | 22 | runs: 23 | using: 'composite' 24 | steps: 25 | - name: Set up Python 26 | uses: actions/setup-python@v4 27 | with: 28 | python-version: '3.10.11' 29 | 30 | - name: Install Bandit 31 | shell: bash 32 | run: | 33 | python -m pip install --upgrade pip 34 | pip install bandit 35 | 36 | - name: Run Bandit Scan 37 | shell: bash 38 | continue-on-error: true 39 | run: | 40 | bandit -r . -f json -o ${{ inputs.report_name }}.json 41 | 42 | - name: Upload Bandit Scan Results 43 | if: ${{ inputs.upload_to_artifactory == 'true' || inputs.run_bandit_scan == 'true' }} 44 | uses: actions/upload-artifact@v4 45 | with: 46 | name: ${{ inputs.report_name }} 47 | path: ${{ inputs.report_name }}.json 48 | -------------------------------------------------------------------------------- /.github/actions/envsetup/README.md: -------------------------------------------------------------------------------- 1 | # Setup Python and Package 2 | 3 | This GitHub Action sets up Python and installs necessary packages. 4 | 5 | ## Inputs 6 | 7 | - `python-version` (optional): Python version to use. Default is `3.10.11`. 8 | 9 | ## Permissions 10 | 11 | This action requires read permissions for all available permissions. 12 | ```yaml 13 | permissions: read-all 14 | ``` 15 | 16 | ## Usage 17 | 18 | ```yaml 19 | 20 | name: Setup Python and Package 21 | description: This action sets up Python and installs necessary packages. 22 | inputs: 23 | python-version: 24 | description: 'Python version to use' 25 | required: false 26 | default: '3.10.11' 27 | 28 | runs: 29 | using: "composite" 30 | steps: 31 | - name: Set up Python 32 | uses: actions/setup-python@v4 33 | with: 34 | python-version: '3.10.11' 35 | # This step sets up the Python environment with the specified version. 36 | 37 | - name: Verify Python in PATH and Install dependencies 38 | run: | 39 | python --version 40 | python -m pip install --upgrade pip 41 | python -m pip install pyinstaller 42 | python -m pip install pyinstaller-versionfile 43 | shell: pwsh 44 | # This step verifies Python is in the PATH and installs necessary dependencies using pip. 45 | 46 | - name: Verify PyInstaller Installation 47 | run: | 48 | python --version 49 | pyinstaller --version 50 | shell: pwsh 51 | # This step verifies the installation of PyInstaller by checking its version. -------------------------------------------------------------------------------- /.github/actions/buildartifact/README.md: -------------------------------------------------------------------------------- 1 | # Build The Project 2 | 3 | This GitHub Action builds the project and uploads it to the Artifactory. 4 | 5 | ## Inputs 6 | 7 | - `upload_to_artifactory` (optional): Flag to control whether to upload to Artifactory. Default is `false`. 8 | 9 | ## Permissions 10 | 11 | This action requires read permissions for all available permissions. 12 | ```yaml 13 | permissions: read-all 14 | ``` 15 | 16 | ## Parameters 17 | 18 | ```yaml 19 | upload_to_artifactory: 20 | description: 'Flag to control whether to upload to Artifactory' 21 | required: false 22 | default: 'false' 23 | ``` 24 | 25 | ## This step runs the build script using PowerShell. 26 | ```yaml 27 | - name: Run Build 28 | run: | 29 | cd build 30 | .\Build.bat 31 | shell: pwsh 32 | ``` 33 | 34 | ## This step prepares the files for upload by copying them to the upload directory. 35 | ```yaml 36 | - name: Prepare files for upload 37 | run: | 38 | mkdir -p upload 39 | cp dist/* upload/ 40 | cp -r AIDevKit upload/ 41 | cp CHANGELOG.md upload/ 42 | cp License.txt upload/ 43 | cp Installation_Guide.md upload/README.md 44 | shell: pwsh 45 | ``` 46 | 47 | ## This step uploads the prepared files as an artifact to Artifactory if the corresponding flag is set. 48 | ```yaml 49 | - name: Upload binary as artifact 50 | if: ${{ inputs.upload_to_artifactory == 'true' }} 51 | uses: actions/upload-artifact@v4 52 | with: 53 | name: ArtifactAIPC 54 | path: upload/ 55 | ``` 56 | -------------------------------------------------------------------------------- /.github/actions/linting/action.yml: -------------------------------------------------------------------------------- 1 | name: 'Lint Action' 2 | description: 'Perform linting for project' 3 | inputs: 4 | run_linting: 5 | description: 'Run Linting and also upload to artifactory' 6 | required: true 7 | default: 'false' 8 | upload_to_artifactory: 9 | description: 'Flag to control whether to upload reports to Artifactory' 10 | required: false 11 | default: 'false' 12 | 13 | permissions: 14 | contents: read 15 | #Adding Permission as Read for all of the available permissions 16 | 17 | runs: 18 | using: 'composite' 19 | steps: 20 | - name: Set up Python 21 | uses: actions/setup-python@v4 22 | with: 23 | python-version: '3.10.11' 24 | 25 | - name: Install linting tools 26 | run: | 27 | python -m pip install --upgrade pip 28 | pip install flake8 pylint black isort 29 | pip install flake8-html pylint-report 30 | shell: bash 31 | 32 | - name: Run Black Formatting Check 33 | continue-on-error: true 34 | run: | 35 | mkdir -p reports/black 36 | black --check . > reports/black/formatting-check.txt 37 | shell: bash 38 | 39 | - name: Run Flake8 Linting 40 | continue-on-error: true 41 | run: | 42 | mkdir -p reports/flake8 43 | flake8 --format=html --htmldir=reports/flake8 . 44 | shell: bash 45 | 46 | - name: Run Pylint 47 | continue-on-error: true 48 | run: | 49 | mkdir -p reports/pylint 50 | pylint **/*.py > reports/pylint/pylint-report.txt 51 | shell: bash 52 | 53 | - name: Run Isort Import Sorting Check 54 | continue-on-error: true 55 | run: | 56 | mkdir -p reports/isort 57 | isort --check-only . > reports/isort/import-check.txt 58 | shell: bash 59 | 60 | - name: Upload Linting Reports 61 | if: ${{ inputs.upload_to_artifactory == 'true' || inputs.run_linting == 'true' }} 62 | uses: actions/upload-artifact@v4 63 | with: 64 | name: linting-reports 65 | path: reports/ -------------------------------------------------------------------------------- /.github/actions/scans/trivy/action.yml: -------------------------------------------------------------------------------- 1 | name: 'Trivy Vulnerability Scan' 2 | description: 'Perform vulnerability scanning using Trivy' 3 | inputs: 4 | # Trivy Parameters 5 | scan-ref: 6 | description: 'Scan reference' 7 | required: true 8 | default: 'requirements.txt' 9 | scan-type: 10 | description: 'Scan type to use for scanning vulnerability' 11 | required: true 12 | default: 'fs' 13 | scanners: 14 | description: 'Comma-separated list of security issues to detect' 15 | required: true 16 | default: 'vuln,secret,misconfig,license' 17 | severity: 18 | description: 'Severities of vulnerabilities to display' 19 | required: false 20 | default: 'UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL' 21 | report_name: 22 | description: 'Name of the report file' 23 | required: false 24 | default: 'trivy-results' 25 | upload_to_artifactory: 26 | description: 'Flag to control whether to upload the results to Artifactory' 27 | required: false 28 | default: 'false' 29 | run_trivy_scan: 30 | description: 'run trivy scand and also upload to artifactory' 31 | required: false 32 | default: 'false' 33 | 34 | # Adding read permissions for all available permissions 35 | permissions: read-all 36 | 37 | runs: 38 | using: 'composite' 39 | steps: 40 | - name: Set up Python 41 | uses: actions/setup-python@v4 42 | with: 43 | python-version: '3.10.11' 44 | 45 | - name: Run Trivy vulnerability scanner in fs mode 46 | uses: aquasecurity/trivy-action@0.28.0 47 | with: 48 | scan-type: ${{ inputs.scan-type }} 49 | scan-ref: ${{ inputs.scan-ref }} 50 | severity: ${{ inputs.severity }} 51 | format: 'json' 52 | output: ${{ inputs.report_name }}.json 53 | scanners: ${{ inputs.scanners }} 54 | 55 | - name: Upload Vulnerability Scan Results 56 | if: ${{ inputs.upload_to_artifactory == 'true' || inputs.run_trivy_scan=='true' }} 57 | uses: actions/upload-artifact@v4 58 | with: 59 | name: ${{ inputs.report_name }} 60 | path: ${{ inputs.report_name }}.json -------------------------------------------------------------------------------- /.github/actions/scans/bandit/README.md: -------------------------------------------------------------------------------- 1 | # Bandit Actions Scan 2 | 3 | This GitHub Action performs security scanning using Bandit. 4 | 5 | ## Inputs 6 | 7 | - `report_name` (optional): The name of the report file. Default is `bandit-results`. 8 | - `upload_to_artifactory` (optional): Flag to control whether to upload to Artifactory. Default is `false`. 9 | - `run_bandit_scan` (optional): Flag to control whether to run the Bandit scan and upload to Artifactory. Default is `false`. 10 | 11 | ## Permissions 12 | 13 | This action requires read permissions for all available permissions. 14 | ```yaml 15 | permissions: read-all 16 | ``` 17 | 18 | ## Parameters 19 | 20 | ```yaml 21 | report_name: 22 | description: 'Name of the report file' 23 | required: false 24 | default: 'bandit-results' 25 | upload_to_artifactory: 26 | description: 'Flag to control whether to upload to Artifactory' 27 | required: false 28 | default: 'false' 29 | run_bandit_scan: 30 | description: 'run bandit scan and also upload to artifactory' 31 | required: false 32 | default: 'false' 33 | ``` 34 | 35 | ## This step sets up the Python environment with the specified version. 36 | 37 | ```yaml 38 | - name: Set up Python 39 | uses: actions/setup-python@v4 40 | with: 41 | python-version: '3.10.11' 42 | ``` 43 | ## This step installs Bandit using pip. 44 | 45 | ```yaml 46 | - name: Install Bandit 47 | shell: bash 48 | run: | 49 | python -m pip install --upgrade pip 50 | pip install bandit 51 | ``` 52 | 53 | ## This step runs the Bandit scan on the repository and outputs the results in JSON format. 54 | ```yaml 55 | - name: Run Bandit Scan 56 | shell: bash 57 | continue-on-error: true 58 | run: | 59 | bandit -r . -f json -o ${{ inputs.report_name }}.json 60 | ``` 61 | 62 | ## This step uploads the Bandit scan results to Artifactory if the corresponding flags are set. 63 | ```yaml 64 | - name: Upload Bandit Scan Results 65 | if: ${{ inputs.upload_to_artifactory == 'true' || inputs.run_bandit_scan == 'true' }} 66 | uses: actions/upload-artifact@v4 67 | with: 68 | name: ${{ inputs.report_name }} 69 | path: ${{ inputs.report_name }}.json 70 | ``` 71 | -------------------------------------------------------------------------------- /Linux_Software_Installation/Utilities/compatibility_check_README.md: -------------------------------------------------------------------------------- 1 | # Intel Driver Compatibility Checker (Optional Standalone Tool) 2 | 3 | > **Note**: Compatibility checking is now **integrated into the main script**. Most users should use: 4 | > ```bash 5 | > ./build-static-installer.sh --build-static 6 | > ``` 7 | > This standalone tool is **optional** and primarily useful for development, debugging, or testing specific version combinations. 8 | 9 | This script helps identify and resolve version compatibility issues between Intel Graphics Compiler (IGC) and Intel Compute Runtime packages. 10 | 11 | ## Problem 12 | 13 | When using the latest Intel drivers, you may encounter dependency conflicts like: 14 | ``` 15 | dpkg: dependency problems prevent configuration of intel-opencl-icd: 16 | intel-opencl-icd depends on intel-igc-opencl-2 (= 2.12.5); however: 17 | Version of intel-igc-opencl-2 on system is 2.14.1 18 | ``` 19 | 20 | This happens because the Intel Graphics Compiler and Compute Runtime are released independently, and the latest versions may not always be compatible. 21 | 22 | ## Solution 23 | 24 | The `compatibility_check.sh` script: 25 | 1. 📡 Downloads package metadata from GitHub releases 26 | 2. 🔍 Analyzes dependency requirements in .deb packages 27 | 3. ✅ Identifies compatible version combinations 28 | 4. 🛡️ Prevents installation of incompatible driver sets 29 | 30 | ## Usage 31 | 32 | ### Check Latest Versions 33 | ```bash 34 | ./compatibility_check.sh --check 35 | ``` 36 | 37 | ### Check Specific Versions (Debugging) 38 | ```bash 39 | ./compatibility_check.sh --igc-tag v2.14.1 --runtime-tag 25.22.33944.8 40 | ``` 41 | 42 | ### Example Output 43 | ``` 44 | [INFO] IGC package version: 2.14.1 45 | [INFO] Required IGC version: 2.12.5 46 | [ERROR] ❌ Version mismatch detected! 47 | [ERROR] IGC provides: 2.14.1 48 | [ERROR] Runtime needs: 2.12.5 49 | ``` 50 | 51 | ## Environment Variables 52 | 53 | - `GITHUB_TOKEN`: Personal access token for higher API rate limits (recommended) 54 | 55 | ## Integration Status 56 | 57 | ✅ **Compatibility checking is now integrated** into `verify_latest_driver_names.sh --build-static` 58 | 59 | This standalone script is **optional** and mainly useful for: 60 | - 🔧 **Development/debugging**: Testing specific version combinations 61 | - 📊 **Manual verification**: Quick compatibility checks without generating static script 62 | - 🛠️ **Troubleshooting**: Advanced users who want detailed compatibility analysis 63 | 64 | ## Requirements 65 | 66 | - `jq` - JSON processor 67 | - `curl` - HTTP client 68 | - `dpkg-deb` - Debian package tools 69 | - Internet connectivity to GitHub 70 | 71 | ## Install Requirements 72 | 73 | ```bash 74 | sudo apt install jq curl 75 | ``` 76 | -------------------------------------------------------------------------------- /.github/actions/linting/README.md: -------------------------------------------------------------------------------- 1 | # Lint Action 2 | 3 | This GitHub Action performs linting for the project using various tools. 4 | 5 | ## Inputs 6 | 7 | - `run_linting` (required): Run linting and also upload to Artifactory. Default is `false`. 8 | - `upload_to_artifactory` (optional): Flag to control whether to upload reports to Artifactory. Default is `false`. 9 | 10 | ## Permissions 11 | 12 | This action requires read permissions for all available permissions. 13 | ```yaml 14 | permissions: read-all 15 | ``` 16 | 17 | ## Parameters 18 | 19 | ```yaml 20 | upload_to_artifactory: 21 | description: 'Flag to control whether to upload reports to Artifactory' 22 | required: false 23 | default: 'false' 24 | run_linting: 25 | description: 'Run Linting and also upload to artifactory' 26 | required: true 27 | default: 'false' 28 | ``` 29 | ## This step sets up the Python environment with the specified version. 30 | ```yaml 31 | - name: Set up Python 32 | uses: actions/setup-python@v4 33 | with: 34 | python-version: '3.10.11' 35 | ``` 36 | 37 | ## This step installs the necessary linting tools using pip. 38 | ```yaml 39 | - name: Install linting tools 40 | run: | 41 | python -m pip install --upgrade pip 42 | pip install flake8 pylint black isort 43 | pip install flake8-html pylint-report 44 | shell: bash 45 | ``` 46 | 47 | ## This step runs Black to check the formatting of the code and outputs the results to a file. 48 | ```yaml 49 | - name: Run Black Formatting Check 50 | continue-on-error: true 51 | run: | 52 | mkdir -p reports/black 53 | black --check . > reports/black/formatting-check.txt 54 | shell: bash 55 | ``` 56 | 57 | ## This step runs Flake8 to lint the code and outputs the results in HTML format. 58 | ```yaml 59 | - name: Run Flake8 Linting 60 | continue-on-error: true 61 | run: | 62 | mkdir -p reports/flake8 63 | flake8 --format=html --htmldir=reports/flake8 . 64 | shell: bash 65 | ``` 66 | 67 | ## This step runs Pylint to lint the Python files and outputs the results to a file. 68 | ```yaml 69 | - name: Run Pylint 70 | continue-on-error: true 71 | run: | 72 | mkdir -p reports/pylint 73 | pylint **/*.py > reports/pylint/pylint-report.txt 74 | shell: bash 75 | ``` 76 | 77 | ## This step runs Isort to check the import sorting and outputs the results to a file. 78 | ```yaml 79 | - name: Run Isort Import Sorting Check 80 | continue-on-error: true 81 | run: | 82 | mkdir -p reports/isort 83 | isort --check-only . > reports/isort/import-check.txt 84 | shell: bash 85 | ``` 86 | 87 | ## This step uploads the linting reports to Artifactory if the corresponding flags are set. 88 | ```yaml 89 | - name: Upload Linting Reports 90 | if: ${{ inputs.upload_to_artifactory == 'true' || inputs.run_linting == 'true' }} 91 | uses: actions/upload-artifact@v4 92 | with: 93 | name: linting-reports 94 | path: reports/ 95 | ``` -------------------------------------------------------------------------------- /.github/actions/scans/trivy/README.md: -------------------------------------------------------------------------------- 1 | # Trivy Vulnerability Scan 2 | 3 | This GitHub Action performs vulnerability scanning using Trivy. 4 | 5 | ## Inputs 6 | 7 | - `scan-ref` (optional): Scan reference. Default is `requirements.txt`. 8 | - `scan-type` (optional): Scan type to use for scanning vulnerability. Default is `fs`. 9 | - `scanners` (optional): Comma-separated list of security issues to detect. Default is `vuln,secret,misconfig,license`. 10 | - `severity` (optional): Severities of vulnerabilities to display. Default is `UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL`. 11 | - `report_name` (optional): Name of the report file. Default is `trivy-results`. 12 | - `upload_to_artifactory` (optional): Flag to control whether to upload the results to Artifactory. Default is `false`. 13 | - `run_trivy_scan` (optional): Flag to control whether to run the Trivy scan and upload to Artifactory. Default is `false`. 14 | 15 | ## Permissions 16 | 17 | This action requires read permissions for all available permissions. 18 | ```yaml 19 | permissions: read-all 20 | ``` 21 | 22 | ## Parameters 23 | 24 | ```yaml 25 | scan-ref: 26 | description: 'Scan reference' 27 | required: false 28 | default: 'requirements.txt' 29 | scan-type: 30 | description: 'Scan type to use for scanning vulnerability' 31 | required: false 32 | default: 'fs' 33 | scanners: 34 | description: 'Comma-separated list of security issues to detect' 35 | required: false 36 | default: 'vuln,secret,misconfig,license' 37 | severity: 38 | description: 'Severities of vulnerabilities to display' 39 | required: false 40 | default: 'UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL' 41 | report_name: 42 | description: 'Name of the report file' 43 | required: false 44 | default: 'trivy-results' 45 | upload_to_artifactory: 46 | description: 'Flag to control whether to upload the results to Artifactory' 47 | required: false 48 | default: 'false' 49 | run_trivy_scan: 50 | description: 'run trivy scan and also upload to artifactory' 51 | required: false 52 | default: 'false' 53 | ``` 54 | 55 | ## This step sets up the Python environment with the specified version. 56 | ```yaml 57 | - name: Set up Python 58 | uses: actions/setup-python@v4 59 | with: 60 | python-version: '3.10.11' 61 | ``` 62 | 63 | ## This step runs the Trivy vulnerability scanner in filesystem mode and outputs the results in JSON format. 64 | ```yaml 65 | - name: Run Trivy vulnerability scanner in fs mode 66 | uses: aquasecurity/trivy-action@0.28.0 67 | with: 68 | scan-type: ${{ inputs.scan-type }} 69 | scan-ref: ${{ inputs.scan-ref }} 70 | severity: ${{ inputs.severity }} 71 | format: 'json' 72 | output: ${{ inputs.report_name }}.json 73 | scanners: ${{ inputs.scanners }} 74 | ``` 75 | 76 | ## This step uploads the Trivy scan results to Artifactory if the corresponding flags are set. 77 | ```yaml 78 | - name: Upload Vulnerability Scan Results 79 | # if: ${{ inputs.upload_to_artifactory == 'true' || inputs.run_trivy_scan == 'true' }} 80 | uses: actions/upload-artifact@v4 81 | with: 82 | name: ${{ inputs.report_name }} 83 | path: ${{ inputs.report_name }}.json 84 | ``` -------------------------------------------------------------------------------- /.github/actions/scans/clamav/action.yml: -------------------------------------------------------------------------------- 1 | name: 'ClamAV Security Scan' 2 | description: 'Perform virus scanning using ClamAV' 3 | inputs: 4 | # ClamAV Parameters 5 | exclude_paths: 6 | description: 'Directories to exclude from scan, provide with a comma separated string. i.e. node_modules,.git,__pycache__' 7 | required: false 8 | default: '.git' 9 | 10 | # input parameter for artifactory 11 | run_clamav_scan: 12 | description: 'run clamav and also upload to artifactory' 13 | required: true 14 | default: 'false' 15 | report_name: 16 | description: 'Name of the report file' 17 | required: false 18 | default: 'clamscan-results' 19 | artifact_name: 20 | description: 'Provide the Artifact Name to download for Artifact Scanning' 21 | required: false 22 | artifact_path: 23 | description: 'Provide the Artifact Download Location for Artifact Scanning' 24 | required: false 25 | default: './ArtifactAIPC' 26 | upload_to_artifactory: 27 | description: 'Flag to control whether to upload to Artifactory' 28 | required: false 29 | default: 'false' 30 | 31 | 32 | permissions: read-all 33 | # Adding Permission as Read for all of the available permissions 34 | 35 | runs: 36 | using: 'composite' 37 | steps: 38 | - name: Download artifact 39 | if: ${{ inputs.artifact_name != '' && inputs.artifact_path != '' && inputs.upload_to_artifactory == 'true' }} 40 | uses: actions/download-artifact@v4 41 | with: 42 | name: ${{ inputs.artifact_name }} 43 | path: ${{ inputs.artifact_path }} 44 | 45 | - name: Show downloaded artifact content 46 | if: ${{ inputs.artifact_name != '' && inputs.artifact_path != '' && inputs.upload_to_artifactory == 'true' }} 47 | run: | 48 | echo "Listing contents of the downloaded artifact:" 49 | ls -R ${{ inputs.artifact_path }} 50 | shell: bash 51 | 52 | - name: Install ClamAV 53 | run: | 54 | sudo apt-get update 55 | sudo apt-get install -y clamav clamav-daemon 56 | sudo systemctl stop clamav-freshclam 57 | shell: bash 58 | 59 | # Step 3: Update virus database 60 | - name: Update Virus Database 61 | run: | 62 | sudo freshclam 63 | sudo systemctl start clamav-freshclam 64 | shell: bash 65 | 66 | - name: Verify installation 67 | run: | 68 | clamscan --version 69 | shell: bash 70 | 71 | - name: Run ClamAV Virus Scan 72 | shell: bash 73 | continue-on-error: true 74 | run: | 75 | # Define directories to exclude 76 | EXCLUDE_DIRS="${{ inputs.exclude_paths }}" 77 | 78 | # Build the --exclude-dir flags 79 | EXCLUDE_FLAGS="" 80 | IFS=',' read -ra DIRS <<< "$EXCLUDE_DIRS" 81 | for DIR in "${DIRS[@]}"; do 82 | EXCLUDE_FLAGS+="--exclude-dir=$DIR " 83 | done 84 | 85 | # Determine the directory to scan 86 | if [ -n "${{ inputs.artifact_name }}" ]; then 87 | SCAN_DIR="${{ inputs.artifact_name }}" 88 | else 89 | SCAN_DIR="." 90 | fi 91 | 92 | # Run ClamAV scan 93 | clamscan -r $SCAN_DIR $EXCLUDE_FLAGS --verbose --detect-pua --alert-broken --log=${{ inputs.report_name }}.log 94 | 95 | # Check scan results 96 | SCAN_RESULT=$? 97 | 98 | cat ${{ inputs.report_name }}.log 99 | 100 | # Fail the workflow if viruses are found 101 | # Exit codes: 0 = No viruses, 1 = Viruses found, 2 = Error 102 | if [ $SCAN_RESULT -eq 1 ]; then 103 | echo "**ClamAV**: ⚠️ Virus detected! Please review the ClamAV scan reports." 104 | exit 1 105 | elif [ $SCAN_RESULT -eq 2 ]; then 106 | echo "ClamAV scan encountered an error!" 107 | fi 108 | 109 | - name: Upload ClamAV Scan Results 110 | if: ${{ inputs.upload_to_artifactory == 'true' || inputs.run_clamav_scan == 'true'}} 111 | uses: actions/upload-artifact@v4 112 | with: 113 | name: ${{ inputs.report_name }} 114 | path: ${{ inputs.report_name }}.log -------------------------------------------------------------------------------- /Windows_Software_Installation/OVMS/README_OVMS.md: -------------------------------------------------------------------------------- 1 | # OVMS Launcher 2 | 3 | A PowerShell script that downloads, configures, and starts OpenVINO Model Server. 4 | 5 | ## Quick Start 6 | 7 | ```powershell 8 | # Start text model on GPU (default) 9 | .\ovms_setup.ps1 10 | 11 | # Start text model on CPU 12 | .\ovms_setup.ps1 -Target CPU 13 | 14 | # Start text model on NPU (Intel AI PC) 15 | .\ovms_setup.ps1 -Target NPU 16 | 17 | # Start image generation on GPU 18 | .\ovms_setup.ps1 -Model image 19 | 20 | # Start custom model 21 | .\ovms_setup.ps1 -Model "OpenVINO/Mistral-7B-Instruct-v0.2-int4-cw-ov" -Target NPU 22 | ``` 23 | 24 | ## Features 25 | 26 | - **One Command**: Downloads OVMS, downloads models, starts server 27 | - **Smart Defaults**: Automatically selects best model for each device 28 | - **Auto Download**: Models download automatically from Hugging Face 29 | - **Device Optimized**: Different models optimized for GPU/CPU/NPU 30 | 31 | ## Default Models 32 | 33 | ### Text Generation 34 | - **GPU/CPU**: `OpenVINO/Phi-3.5-mini-instruct-int4-ov` 35 | - **NPU**: `OpenVINO/Phi-3.5-mini-instruct-int4-cw-ov` (NPU-optimized) 36 | 37 | ### Image Generation 38 | - **GPU**: `OpenVINO/FLUX.1-schnell-int4-ov` 39 | - **CPU**: `OpenVINO/stable-diffusion-v1-5-int8-ov` 40 | 41 | ## Parameters 42 | 43 | - `-Model`: "text" (default), "image", or full OpenVINO model name 44 | - `-Target`: "GPU" (default), "CPU", or "NPU" 45 | - `-Port`: REST API port (default: 8000) 46 | - `-Help`: Show detailed help message 47 | 48 | ## Getting Help 49 | 50 | The script includes comprehensive help options: 51 | 52 | ```powershell 53 | # Show built-in help with examples 54 | .\ovms_setup.ps1 -Help 55 | 56 | # PowerShell native help 57 | Get-Help .\ovms_setup.ps1 58 | Get-Help .\ovms_setup.ps1 -Examples 59 | Get-Help .\ovms_setup.ps1 -Detailed 60 | ``` 61 | 62 | ## Examples 63 | 64 | ```powershell 65 | # Basic usage 66 | .\ovms_setup.ps1 # Phi-3 on GPU 67 | .\ovms_setup.ps1 -Target CPU # Phi-3 on CPU 68 | .\ovms_setup.ps1 -Target NPU # Phi-3 on NPU 69 | .\ovms_setup.ps1 -Model image # FLUX on GPU 70 | 71 | # Custom models 72 | .\ovms_setup.ps1 -Model "OpenVINO/gpt-j-6b-int4-cw-ov" -Target NPU 73 | .\ovms_setup.ps1 -Model "OpenVINO/stable-diffusion-v1-5-fp16-ov" -Target GPU 74 | .\ovms_setup.ps1 -Model "OpenVINO/Mistral-7B-Instruct-v0.2-int4-cw-ov" -Target CPU 75 | 76 | # Custom port 77 | .\ovms_setup.ps1 -Port 9000 78 | ``` 79 | 80 | ## API Access 81 | 82 | Once started, the API is available at: `http://localhost:8000/v3` 83 | 84 | ### Test with curl: 85 | ```bash 86 | (Invoke-WebRequest -Uri "http://localhost:8000/v3/chat/completions" ` 87 | -Method POST ` 88 | -Headers @{ "Content-Type" = "application/json" } ` 89 | -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 90 | 91 | ``` 92 | 93 | ### Test with Python: 94 | ```python 95 | from openai import OpenAI 96 | 97 | client = OpenAI( 98 | base_url="http://localhost:8000/v3", 99 | api_key="unused" 100 | ) 101 | 102 | response = client.chat.completions.create( 103 | model="OpenVINO/Phi-3.5-mini-instruct-int4-ov", 104 | messages=[{"role": "user", "content": "Hello!"}], 105 | max_tokens=50 106 | ) 107 | 108 | print(response.choices[0].message.content) 109 | ``` 110 | 111 | ## What It Does 112 | 113 | 1. **Downloads OVMS**: Automatically downloads OpenVINO Model Server v2025.2.1 if not present 114 | 2. **Initializes Environment**: Runs setupvars.ps1 to properly configure OpenVINO environment 115 | 3. **Selects Model**: Chooses the best model for your target device 116 | 4. **Downloads Model**: Downloads the model from Hugging Face Hub automatically 117 | 5. **Starts Server**: Launches OVMS with optimal parameters for the model type 118 | 6. **Ready to Use**: API available immediately at the specified port 119 | 120 | ## Requirements 121 | 122 | - Windows PowerShell 5.1+ or PowerShell Core 7+ 123 | - Internet connection (for downloads) 124 | - For NPU: Intel AI PC with NPU drivers 125 | 126 | ## Device Recommendations 127 | 128 | - **GPU**: Fastest performance, best for production 129 | - **CPU**: Works everywhere, good for development 130 | - **NPU**: power efficient 131 | 132 | ## Stop Server 133 | 134 | Press `Ctrl+C` to stop the server. 135 | -------------------------------------------------------------------------------- /Linux_Software_Installation/Utilities/verify_connectivity.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Simple test script to show what driver versions would be downloaded 4 | # This version has more robust error handling and debugging 5 | 6 | echo "=== Simple Driver Version Test ===" 7 | echo 8 | echo "Note: This script uses the GitHub API which has rate limits." 9 | 10 | # Check GitHub token status 11 | if [ -n "$GITHUB_TOKEN" ]; then 12 | echo "✓ GitHub token is configured (${#GITHUB_TOKEN} characters)" 13 | echo " This will allow higher rate limits and better reliability." 14 | else 15 | echo "⚠ No GitHub token found in environment" 16 | echo " Recommendation: Set GITHUB_TOKEN for better reliability:" 17 | echo " 1. Get a token at: https://github.com/settings/tokens" 18 | echo " 2. export GITHUB_TOKEN=your_token_here" 19 | echo " 3. Re-run this script" 20 | fi 21 | echo 22 | 23 | # Test HTTPS connectivity 24 | echo "1. Testing HTTPS connectivity..." 25 | if curl -s --connect-timeout 5 --max-time 10 https://github.com > /dev/null; then 26 | echo " ✓ Can reach github.com via HTTPS" 27 | else 28 | echo " ✗ Cannot reach github.com via HTTPS" 29 | exit 1 30 | fi 31 | 32 | # Test GitHub API basic endpoint 33 | echo "2. Testing GitHub API..." 34 | if [ -n "$GITHUB_TOKEN" ]; then 35 | echo " ✓ GitHub token is set (length: ${#GITHUB_TOKEN} characters)" 36 | echo " Using authenticated requests..." 37 | API_RESPONSE=$(curl -s --connect-timeout 5 --max-time 10 -H "Authorization: token $GITHUB_TOKEN" https://api.github.com) 38 | else 39 | echo " ⚠ No GitHub token set - using unauthenticated requests" 40 | echo " Note: This may hit rate limits quickly. Set GITHUB_TOKEN for better reliability." 41 | API_RESPONSE=$(curl -s --connect-timeout 5 --max-time 10 https://api.github.com) 42 | fi 43 | 44 | if [ $? -eq 0 ] && echo "$API_RESPONSE" | grep -q "current_user_url"; then 45 | echo " ✓ GitHub API is accessible" 46 | elif echo "$API_RESPONSE" | grep -q "rate limit exceeded"; then 47 | echo " ✗ GitHub API rate limit exceeded" 48 | echo 49 | echo " To fix this issue:" 50 | echo " 1. Set your GitHub token: export GITHUB_TOKEN=your_token_here" 51 | echo " 2. Get a token at: https://github.com/settings/tokens" 52 | echo " 3. Re-run this script" 53 | echo 54 | exit 1 55 | else 56 | echo " ✗ GitHub API is not accessible" 57 | echo " Response: $API_RESPONSE" 58 | exit 1 59 | fi 60 | 61 | # Simple function to get version with verbose output 62 | get_version_simple() { 63 | local repo="$1" 64 | echo " Trying to fetch version for $repo..." 65 | 66 | local url="https://api.github.com/repos/$repo/releases/latest" 67 | echo " URL: $url" 68 | 69 | local response 70 | if [ -n "$GITHUB_TOKEN" ]; then 71 | echo " Using authenticated request..." 72 | response=$(curl -s --connect-timeout 10 --max-time 30 -H "Authorization: token $GITHUB_TOKEN" "$url") 73 | else 74 | echo " Using unauthenticated request..." 75 | response=$(curl -s --connect-timeout 10 --max-time 30 "$url") 76 | fi 77 | local exit_code=$? 78 | 79 | if [ $exit_code -ne 0 ]; then 80 | echo " curl failed with exit code: $exit_code" 81 | return 1 82 | fi 83 | 84 | if [ -z "$response" ]; then 85 | echo " Empty response" 86 | return 1 87 | fi 88 | 89 | # Check if it's an error response 90 | if echo "$response" | grep -q '"message"'; then 91 | echo " API Error:" 92 | echo "$response" | grep '"message"' | head -1 93 | return 1 94 | fi 95 | 96 | local version=$(echo "$response" | grep '"tag_name":' | head -1 | sed -E 's/.*"tag_name": *"([^"]+)".*/\1/') 97 | 98 | if [ -z "$version" ]; then 99 | echo " Could not parse version from response" 100 | echo " First 200 chars of response: $(echo "$response" | head -c 200)" 101 | return 1 102 | fi 103 | 104 | echo " ✓ Found version: $version" 105 | echo "$version" 106 | } 107 | 108 | echo 109 | echo "3. Testing specific repositories..." 110 | 111 | # Test each repository 112 | repos=( 113 | "intel/intel-graphics-compiler" 114 | "intel/compute-runtime" 115 | "intel/linux-npu-driver" 116 | "oneapi-src/level-zero" 117 | ) 118 | 119 | for repo in "${repos[@]}"; do 120 | echo 121 | echo "Testing $repo:" 122 | version=$(get_version_simple "$repo") 123 | if [ $? -eq 0 ]; then 124 | echo " Result: $version" 125 | else 126 | echo " Result: FAILED" 127 | fi 128 | done 129 | 130 | echo 131 | echo "Test completed!" 132 | -------------------------------------------------------------------------------- /Windows_Software_Installation/WingetGUI_Installer/JSON/install/applications.json: -------------------------------------------------------------------------------- 1 | { 2 | "global_install_flags": "--silent --accept-package-agreements --accept-source-agreements --disable-interactivity --force", 3 | "winget_applications": [ 4 | { 5 | "id": "Microsoft.NuGet", 6 | "friendly_name": "NuGet Package Manager", 7 | "summary": "Package manager for .NET", 8 | "override_flags": null, 9 | "install_location": null, 10 | "version": null, 11 | "version_check": null, 12 | "dependencies": null, 13 | "skip_install": "no" 14 | }, 15 | { 16 | "id": "Microsoft.VisualStudioCode", 17 | "friendly_name": "Visual Studio Code", 18 | "summary": "Code editor", 19 | "override_flags": null, 20 | "install_location": null, 21 | "version": null, 22 | "version_check": null, 23 | "dependencies": null, 24 | "skip_install": "no" 25 | }, 26 | { 27 | "id": "Microsoft.VisualStudio.2022.Community", 28 | "friendly_name": "Visual Studio 2022 Community", 29 | "summary": "Integrated development environment", 30 | "override_flags": "--add Microsoft.VisualStudio.Workload.ManagedDesktop;includeRecommended --add Microsoft.VisualStudio.Workload.NativeDesktop;includeRecommended --quiet --norestart --includeRecommended --wait", 31 | 32 | "install_location": null, 33 | "version": null, 34 | "version_check": null, 35 | "dependencies": null, 36 | "skip_install": "no", 37 | "note": "This package also installs VC++ redistributable, Microsoft .NET SDK" 38 | }, 39 | { 40 | "id": "Python.Python.3.12", 41 | "friendly_name": "Python 3.12", 42 | "summary": "Python programming language interpreter", 43 | "override_flags": null, 44 | "install_location": null, 45 | "version": null, 46 | "version_check": null, 47 | "dependencies": null, 48 | "skip_install": "no" 49 | }, 50 | { 51 | "id": "chrisant996.Clink", 52 | "friendly_name": "Clink", 53 | "summary": "Command line editing enhancements for cmd.exe", 54 | "override_flags": null, 55 | "install_location": null, 56 | "version": null, 57 | "version_check": null, 58 | "dependencies": null, 59 | "skip_install": "no" 60 | }, 61 | { 62 | "id": "Google.Chrome.Canary", 63 | "friendly_name": "Chrome Canary", 64 | "summary": "Next-gen Chrome", 65 | "override_flags": null, 66 | "install_location": null, 67 | "version": null, 68 | "version_check": null, 69 | "dependencies": null, 70 | "skip_install": "no" 71 | }, 72 | { 73 | "id": "Git.Git", 74 | "friendly_name": "Git for Windows", 75 | "summary": "Distributed version control", 76 | "override_flags": null, 77 | "install_location": null, 78 | "version": null, 79 | "version_check": null, 80 | "dependencies": null, 81 | "skip_install": "no" 82 | }, 83 | { 84 | "id": "Kitware.CMake", 85 | "friendly_name": "CMake", 86 | "summary": "Cross-platform build system generator", 87 | "override_flags": null, 88 | "install_location": null, 89 | "version": null, 90 | "version_check": "cmake --version", 91 | "dependencies": [ 92 | { 93 | "name": "Git", 94 | "version": "2.49.0" 95 | } 96 | ], 97 | "skip_install": "no" 98 | }, 99 | { 100 | "id": "astral-sh.uv", 101 | "friendly_name": "uv", 102 | "summary": "Fast Python package installer and resolver", 103 | "override_flags": null, 104 | "install_location": null, 105 | "version": null, 106 | "version_check": "uv --version", 107 | "dependencies": null, 108 | "skip_install": "no" 109 | }, 110 | { 111 | "id": "KhronosGroup.VulkanSDK", 112 | "friendly_name": "Vulkan SDK", 113 | "summary": "Next-generation graphics and compute API", 114 | "override_flags": null, 115 | "install_location": null, 116 | "version": null, 117 | "version_check": null, 118 | "dependencies": null, 119 | "skip_install": "no" 120 | } 121 | ], 122 | "external_applications": [ 123 | { 124 | "name": "one_api_base_toolkit", 125 | "friendly_name": "Intel oneAPI Base Toolkit", 126 | "summary": "Intel's comprehensive suite of development tools", 127 | "source": "https://registrationcenter-download.intel.com/akdlm/IRC_NAS/ae29263e-38b9-4d43-86c3-376d6e0668e7/intel-oneapi-base-toolkit-2025.0.1.47_offline.exe", 128 | "install_flags": "-a --silent --eula accept", 129 | "download_location": ".\\One_API", 130 | "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", 131 | "dependencies": [ 132 | { 133 | "name": "Microsoft.VisualStudio.2022.Community", 134 | "version": "1.100.2" 135 | } 136 | ], 137 | "skip_install": "yes" 138 | } 139 | ] 140 | } 141 | -------------------------------------------------------------------------------- /Windows_Software_Installation/WingetGUI_Installer/Public/Run_Once_Eula.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | Script that has user accept to all EULA agreements for software installed by this script 3 | Author: Ben Odom (benjamin.j.odom@intel.com) 4 | #> 5 | 6 | 7 | Add-Type -AssemblyName System.Windows.Forms 8 | $disclaimer = @' 9 | 10 | This exclusive remote desktop session includes pre-installed software and models 11 | governed by various end-user license agreements ("EULAs") (the term "Session" refers 12 | to this exclusive remote desktop session and all included software and models). 13 | Please click below for more information: 14 | 15 | By clicking Agree and Continue, I hereby agree and consent to these EULAs. 16 | Intel is providing access to this Session for the sole purpose of demonstrating Intel 17 | technology and enabling me to optimize software for Intel systems, and my use of the 18 | Session is strictly limited to this purpose. I further agree that the 19 | Session is provided by Intel "as is" without any express or implied warranty of any kind. 20 | My use of the Session is at my own risk. Intel will not be liable to me under any legal 21 | theory for any losses or damages in connection with the Session 22 | '@ 23 | $box = New-Object -TypeName System.Windows.Forms.Form 24 | $box.ClientSize = New-Object -TypeName System.Drawing.Size -ArgumentList 600, 380 25 | $box.Text = "Legal Disclaimer" 26 | $box.StartPosition = "CenterScreen" 27 | $box.ControlBox = $false 28 | $box.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::FixedDialog 29 | 30 | $label = New-Object -TypeName System.Windows.Forms.Label 31 | $label.Location = New-Object -TypeName System.Drawing.Point -ArgumentList 10, 10 32 | $label.Size = New-Object -TypeName System.Drawing.Size -ArgumentList 450, 260 33 | $label.Text = $disclaimer 34 | $label.Font = New-Object -TypeName System.Drawing.Font -ArgumentList "Arial", 10 35 | $label.AutoSize = $true 36 | $label.Padding = New-Object -TypeName System.Windows.Forms.Padding -ArgumentList 10, 10, 10, 10 37 | 38 | $alink = New-Object -TypeName System.Windows.Forms.LinkLabel 39 | $alink.Text = "Click here for the list of applications and their corresponding EULA" 40 | $alink.Location = New-Object -TypeName System.Drawing.Point -ArgumentList 10, 280 41 | $alink.Size = New-Object -TypeName System.Drawing.Size -ArgumentList 580, 20 42 | $alink.LinkBehavior = [System.Windows.Forms.LinkBehavior]::AlwaysUnderline 43 | $alink.Font = New-Object -TypeName System.Drawing.Font -ArgumentList "Arial", 10 44 | $alink.Add_Click({ 45 | Start-Process -FilePath "https://sdpconnect.intel.com/html/intel_aipc_cloud_access_agreement.htm" 46 | }) 47 | 48 | 49 | 50 | $check_box = New-Object System.Windows.Forms.CheckBox 51 | $check_box.Text = "I have read and understand all the license agreements." 52 | $check_box.AutoSize = $true 53 | $check_box.Location = New-Object System.Drawing.Point -ArgumentList 10, 250 54 | $box.Controls.Add($check_box) 55 | 56 | # Text to pop up of the button is clicked and the checkbox has not been checked 57 | $check_the_box = New-Object -TypeName System.Windows.Forms.Label 58 | $check_the_box.Location = New-Object -TypeName System.Drawing.Point 10, 230 59 | $check_the_box.AutoSize = $true 60 | $check_the_box.Text = "Must check the box acknowledging that you have read and understand the terms" 61 | $check_the_box.ForeColor = [System.Drawing.Color]::Red 62 | $check_the_box.Visible = $false 63 | $box.Controls.Add($check_the_box) 64 | 65 | 66 | 67 | $accept_button = New-Object -TypeName System.Windows.Forms.Button 68 | $accept_button.Location = New-Object -TypeName System.Drawing.Point -ArgumentList 150, 310 69 | $accept_button.Size = New-Object -TypeName System.Drawing.Size -ArgumentList 150, 45 70 | $accept_button.Text = "Agree and Continue" 71 | 72 | $accept_button.Font = New-Object -TypeName System.Drawing.Font -ArgumentList "Arial", 12 73 | $accept_button.TextAlign = [System.Windows.Forms.HorizontalAlignment]::Center 74 | $accept_button.Add_Click( { 75 | if ($check_box.Checked) { 76 | # Return true (0) for agree 77 | $box.DialogResult = [System.Windows.Forms.DialogResult]::OK 78 | $box.Close() 79 | } 80 | else { 81 | $check_the_box.Visible = $true 82 | } 83 | }) 84 | 85 | 86 | 87 | $disagree_button = New-Object -TypeName System.Windows.Forms.Button 88 | $disagree_button.Location = New-Object -TypeName System.Drawing.Point -ArgumentList 310, 310 89 | $disagree_button.Size = New-Object -TypeName System.Drawing.Size -ArgumentList 150, 45 90 | $disagree_button.Text = "Do not accept" 91 | 92 | $disagree_button.Font = New-Object -TypeName System.Drawing.Font -ArgumentList "Arial", 12 93 | $disagree_button.TextAlign = [System.Windows.Forms.HorizontalAlignment]::Center 94 | $disagree_button.Add_Click( { 95 | # Return false (!0) for disagree 96 | $box.DialogResult = [System.Windows.Forms.DialogResult]::No 97 | $box.Close() 98 | }) 99 | 100 | 101 | $box.Controls.Add($label) 102 | $box.Controls.Add($alink) 103 | $box.Controls.Add($accept_button) 104 | $box.Controls.Add($disagree_button) 105 | 106 | # Show the dialog box and return the result 107 | $box.ShowDialog() | Out-Null 108 | # Return the dialog result 109 | if ($box.DialogResult -eq [System.Windows.Forms.DialogResult]::OK) { 110 | exit 0 111 | } else { 112 | exit 1 113 | } -------------------------------------------------------------------------------- /.github/actions/scans/clamav/README.md: -------------------------------------------------------------------------------- 1 | # ClamAV Security Scan 2 | 3 | This GitHub Action performs virus scanning using ClamAV. 4 | 5 | ## Inputs 6 | 7 | - `exclude_paths` (optional): Directories to exclude from scan, provided as a comma-separated string (e.g., `node_modules,.git,__pycache__`). Default is `.git`. 8 | - `run_clamav_scan` (required): Flag to control whether to run the ClamAV scan and upload to Artifactory. Default is `false`. 9 | - `report_name` (optional): The name of the report file. Default is `clamscan-results`. 10 | - `artifact_name` (optional): Provide the Artifact Name to download for Artifact Scanning. 11 | - `artifact_path` (optional): Provide the Artifact Download Location for Artifact Scanning. Default is `./ArtifactAIPC`. 12 | - `upload_to_artifactory` (optional): Flag to control whether to upload to Artifactory. Default is `false`. 13 | 14 | ## Permissions 15 | 16 | This action requires read permissions for all available permissions. 17 | ```yaml 18 | permissions: read-all 19 | ``` 20 | 21 | ## Parameters 22 | 23 | ```yaml 24 | report_name: 25 | description: 'Name of the report file' 26 | required: false 27 | default: 'clamscan-results' 28 | exclude_paths: 29 | description: 'Directories to exclude from scan, provide with a comma separated string. i.e. node_modules,.git,__pycache__' 30 | required: false 31 | default: '.git' 32 | artifact_name: 33 | description: 'Provide the Artifact Name to download for Artifact Scanning' 34 | required: false 35 | artifact_path: 36 | description: 'Provide the Artifact Download Location for Artifact Scanning' 37 | required: false 38 | default: './ArtifactAIPC' 39 | upload_to_artifactory: 40 | description: 'Flag to control whether to upload to Artifactory' 41 | required: false 42 | default: 'false' 43 | run_clamav_scan: 44 | description: 'run clamav and also upload to artifactory' 45 | required: true 46 | default: 'false' 47 | ``` 48 | 49 | ## This step downloads the specified artifact if the artifact name and path are provided and the upload to Artifactory flag is set to do the virus Scan on the Artifacts. 50 | ```yaml 51 | - name: Download artifact 52 | if: ${{ inputs.artifact_name != '' && inputs.artifact_path != '' && inputs.upload_to_artifactory == 'true' }} 53 | uses: actions/download-artifact@v4 54 | with: 55 | name: ${{ inputs.artifact_name }} 56 | path: ${{ inputs.artifact_path }} 57 | ``` 58 | 59 | ## This step lists the contents of the downloaded artifact if the artifact name and path are provided and the upload to Artifactory flag is set. 60 | ```yaml 61 | - name: Show downloaded artifact content 62 | if: ${{ inputs.artifact_name != '' && inputs.artifact_path != '' && inputs.upload_to_artifactory == 'true' }} 63 | run: | 64 | echo "Listing contents of the downloaded artifact:" 65 | ls -R ${{ inputs.artifact_path }} 66 | shell: bash 67 | ``` 68 | 69 | ## This step installs ClamAV and stops the freshclam service. 70 | ```yaml 71 | - name: Install ClamAV 72 | run: | 73 | sudo apt-get update 74 | sudo apt-get install -y clamav clamav-daemon 75 | sudo systemctl stop clamav-freshclam 76 | shell: bash 77 | ``` 78 | 79 | ## This step updates the ClamAV virus database and starts the freshclam service. 80 | ```yaml 81 | - name: Update Virus Database 82 | run: | 83 | sudo freshclam 84 | sudo systemctl start clamav-freshclam 85 | shell: bash 86 | ``` 87 | 88 | ## This step verifies the ClamAV installation by checking its version. 89 | ```yaml 90 | - name: Verify installation 91 | run: | 92 | clamscan --version 93 | shell: bash 94 | ``` 95 | 96 | ## This step runs the ClamAV virus scan on the specified directory, excluding the specified paths, and outputs the results to a log file. 97 | ```yaml 98 | - name: Run ClamAV Virus Scan 99 | shell: bash 100 | continue-on-error: true 101 | run: | 102 | # Define directories to exclude 103 | EXCLUDE_DIRS="${{ inputs.exclude_paths }}" 104 | 105 | # Build the --exclude-dir flags 106 | EXCLUDE_FLAGS="" 107 | IFS=',' read -ra DIRS <<< "$EXCLUDE_DIRS" 108 | for DIR in "${DIRS[@]}"; do 109 | EXCLUDE_FLAGS+="--exclude-dir=$DIR " 110 | done 111 | 112 | # Determine the directory to scan 113 | if [ -n "${{ inputs.artifact_name }}" ]; then 114 | SCAN_DIR="${{ inputs.artifact_path }}" 115 | else 116 | SCAN_DIR="." 117 | fi 118 | 119 | # Run ClamAV scan 120 | clamscan -r $SCAN_DIR $EXCLUDE_FLAGS --verbose --detect-pua --alert-broken --log=${{ inputs.report_name }}.log 121 | 122 | # Check scan results 123 | SCAN_RESULT=$? 124 | 125 | cat ${{ inputs.report_name }}.log 126 | 127 | # Fail the workflow if viruses are found 128 | # Exit codes: 0 = No viruses, 1 = Viruses found, 2 = Error 129 | if [ $SCAN_RESULT -eq 1 ]; then 130 | echo "**ClamAV**: ⚠️ Virus detected! Please review the ClamAV scan reports." 131 | exit 1 132 | elif [ $SCAN_RESULT -eq 2 ]; then 133 | echo "ClamAV scan encountered an error!" 134 | fi 135 | ``` 136 | 137 | ## This step uploads the ClamAV scan results to Artifactory if the corresponding flags are set. 138 | ```yaml 139 | - name: Upload ClamAV Scan Results 140 | if: ${{ inputs.upload_to_artifactory == 'true' || inputs.run_clamav_scan == 'true'}} 141 | uses: actions/upload-artifact@v4 142 | with: 143 | name: ${{ inputs.report_name }} 144 | path: ${{ inputs.report_name }}.log 145 | ``` -------------------------------------------------------------------------------- /.github/actions/scans/coverity/action.yml: -------------------------------------------------------------------------------- 1 | name: Coverity Scan with Community Credentials 2 | description: "This action installs a specific version of Coverity." 3 | 4 | inputs: 5 | # Coverity Parameters 6 | project: 7 | description: Project name in Coverity Scan. 8 | default: ${{ github.repository }} 9 | required: true 10 | token: 11 | description: Secret project token for accessing Coverity Scan. 12 | required: true 13 | email: 14 | description: Where Coverity Scan should send notifications. 15 | required: true 16 | build_language: 17 | description: Which Coverity Scan language pack to download. 18 | default: other 19 | required: true 20 | build_platform: 21 | description: Which Coverity Scan platform pack to download. 22 | default: linux64 23 | command: 24 | description: Command to pass to cov-build. 25 | default: make 26 | required: true 27 | working-directory: 28 | description: Working directory to set for all steps. 29 | default: ${{ github.workspace }} 30 | version: 31 | description: (Informational) The source version being built. 32 | default: ${{ github.sha }} 33 | description: 34 | description: (Informational) A description for this particular build. 35 | default: coverity-scan-action ${{ github.repository }} / ${{ github.ref }} 36 | 37 | # input parameter for artifactory 38 | report_name: 39 | description: 'Name of the report file' 40 | required: false 41 | default: 'coverity-results' 42 | upload_to_artifactory: 43 | description: 'Flag to control whether to upload to Artifactory' 44 | required: false 45 | default: 'false' 46 | run_coverity_scan: 47 | description: 'run coverity scan and also upload to artifactory' 48 | required: false 49 | default: 'false' 50 | 51 | permissions: read-all 52 | # Setting read permissions for all available scopes to ensure the action has access to necessary resources 53 | 54 | runs: 55 | using: "composite" 56 | steps: 57 | # Need to encode the project name when using in URLs and HTTP forms. Valid 58 | # GitHub project names only have / that need encoding and 59 | # Coverity projects with spaces in their names need encoding so do 60 | # an ad-hoc conversion here. Wait to see if anyone needs something else. 61 | - name: URL encode project name 62 | id: project 63 | run: echo "project=${{ inputs.project }}" | sed -e 's:/:%2F:g' -e 's/ /%20/g' >> $GITHUB_OUTPUT 64 | shell: bash 65 | 66 | # The Coverity site says the tool is usually updated twice yearly, so the 67 | # md5 of download can be used to determine whether there's been an update. 68 | - name: Lookup Coverity Build Tool hash 69 | id: coverity-cache-lookup 70 | run: | 71 | hash=$(curl https://scan.coverity.com/download/${{ inputs.build_language }}/${{ inputs.build_platform }} \ 72 | --data "token=${TOKEN}&project=${{ steps.project.outputs.project }}&md5=1"); \ 73 | echo "hash=${hash}" >> $GITHUB_OUTPUT 74 | shell: bash 75 | env: 76 | TOKEN: ${{ inputs.token }} 77 | 78 | # Try to cache the tool to avoid downloading 1GB+ archive on every run. 79 | # Cache miss will add ~30s to create, but cache hit will save minutes. 80 | - name: Cache Coverity Build Tool 81 | id: cov-build-cache 82 | uses: actions/cache@v4 83 | with: 84 | path: ${{ inputs.working-directory }}/cov-analysis 85 | key: cov-build-${{ inputs.build_language }}-${{ inputs.build_platform }}-${{ steps.coverity-cache-lookup.outputs.hash }} 86 | 87 | - name: Download Coverity Build Tool (${{ inputs.build_language }} / ${{ inputs.build_platform }}) 88 | if: "steps.cov-build-cache.outputs.cache-hit != 'true'" 89 | run: | 90 | curl https://scan.coverity.com/download/${{ inputs.build_language }}/${{ inputs.build_platform }} \ 91 | --no-progress-meter \ 92 | --output cov-analysis.tar.gz \ 93 | --data "token=${TOKEN}&project=${{ steps.project.outputs.project }}" 94 | shell: bash 95 | working-directory: ${{ inputs.working-directory }} 96 | env: 97 | TOKEN: ${{ inputs.token }} 98 | 99 | - if: steps.cov-build-cache.outputs.cache-hit != 'true' 100 | run: mkdir -p cov-analysis 101 | shell: bash 102 | working-directory: ${{ inputs.working-directory }} 103 | 104 | - if: steps.cov-build-cache.outputs.cache-hit != 'true' 105 | run: tar -xzf cov-analysis.tar.gz --strip 1 -C cov-analysis 106 | shell: bash 107 | working-directory: ${{ inputs.working-directory }} 108 | 109 | - name: Build with cov-build 110 | run: | 111 | export PATH="${PWD}/cov-analysis/bin:${PATH}" 112 | cov-build --dir cov-int ${{ inputs.command }} --fs-capture-search-exclude-regex "cov-analysis" 113 | shell: bash 114 | working-directory: ${{ inputs.working-directory }} 115 | 116 | - name: Archive results 117 | run: tar -czvf ${{ inputs.report_name }}.tgz cov-int 118 | shell: bash 119 | working-directory: ${{ inputs.working-directory }} 120 | 121 | - name: Upload Coverity Scan Results 122 | if: ${{ inputs.upload_to_artifactory == 'true' || inputs.run_coverity_scan == 'true'}} 123 | uses: actions/upload-artifact@v4 124 | with: 125 | name: ${{ inputs.report_name }} 126 | path: ${{ inputs.report_name }}.tgz 127 | 128 | - name: Submit results to Coverity Scan 129 | run: | 130 | curl \ 131 | --form token="${TOKEN}" \ 132 | --form email="${{ inputs.email }}" \ 133 | --form file=@${{ inputs.report_name }}.tgz \ 134 | --form version="${{ inputs.version }}" \ 135 | --form description="${{ inputs.description }}" \ 136 | "https://scan.coverity.com/builds?project=${{ steps.project.outputs.project }}" 137 | shell: bash 138 | working-directory: ${{ inputs.working-directory }} 139 | env: 140 | TOKEN: ${{ inputs.token }} 141 | -------------------------------------------------------------------------------- /Windows_Software_Installation/WingetGUI_Installer/Public/Pre_Req.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | This script checks to following: 3 | - Terminal is being run with administrator priviledges 4 | - Winget minimum version 1.10.390 is setup 5 | - NuGet Package Provider is installed 6 | - Microsoft winget client 7 | 8 | #> 9 | $green_check = [char]0x2705 10 | $red_x = [char]0x274C 11 | 12 | <# 13 | Checks to ensure Terminal is being run in admin mode 14 | Returns true if terminal is being run in admin mode 15 | Returns false in all other cases 16 | #> 17 | function CheckIf-Admin() { 18 | $windows_identity = [Security.Principal.WindowsIdentity]::GetCurrent() 19 | $windows_principal = New-Object Security.Principal.WindowsPrincipal($windows_identity) 20 | $is_admin = $windows_principal.IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator) 21 | 22 | if (-not $is_admin) { 23 | return $false 24 | } 25 | return $true 26 | } 27 | 28 | 29 | 30 | <# 31 | Checks the version of winget installed is at least 1.10.390 32 | Returns true if it is a MINIMUM 1.10.390 33 | Return false if winget version is lower than 1.10.390 34 | #> 35 | function Check-Winget() { 36 | $minimum_winget_version = [Version]"1.10.390" 37 | $current_winget_version = winget --version 2>$null 38 | if (-not $current_winget_version) { 39 | return $false 40 | } 41 | $current_winget_version = [Version]($current_winget_version.TrimStart('v')) 42 | if ($current_winget_version -lt $minimum_winget_version) { 43 | return $false 44 | } 45 | else { 46 | return $true 47 | } 48 | } 49 | 50 | 51 | 52 | <# 53 | Checks to ensure that the Microsoft WinGet Client is installed 54 | Returns true if the Winget client module is installed 55 | #> 56 | function Check-WinGet-Client() { 57 | if (Get-InstalledModule -Name "Microsoft.WinGet.Client" -ErrorAction SilentlyContinue) { 58 | return $true 59 | } 60 | else { 61 | return $false 62 | } 63 | 64 | } 65 | 66 | function Check-PreReq() { 67 | if ($Global:external) { 68 | if (-not (CheckIf-Admin)) { 69 | Write-Host "$red_x`: Administrator terminal" 70 | return $false 71 | } 72 | 73 | if (-not (Check-Winget)) { 74 | $user_input = Read-Host "This script requires winget version 1.10.390 minimum to run. Would you like to upgrade? [y/n]" 75 | if ($user_input -eq 'y' -or $user_input -eq "yes" -or $user_input -eq "Y") { 76 | winget upgrade winget 77 | } 78 | else { 79 | Write-Host "Not installing." 80 | return $false 81 | } 82 | } 83 | 84 | 85 | if (-not (Check-WinGet-Client)) { 86 | Write-Host "This script requires the winget client to be installed." -ForegroundColor Yellow 87 | Write-Host "This will also install the NuGet Package Provider." -ForegroundColor Yellow 88 | $user_input = Read-Host "Would you like to install these? [y/n]" 89 | if ($user_input -eq 'y' -or $user_input -eq "yes" -or $user_input -eq "Y") { 90 | Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force 91 | Install-Module -Name Microsoft.WinGet.Client -SkipPublisherCheck -Force 92 | } 93 | else { 94 | Write-Host "Not installing." -ForegroundColor Red 95 | return $false 96 | } 97 | } 98 | 99 | if (CheckIf-Admin -and Check-Winget -and Check-WinGet-Client) { 100 | Write-Host "$green_check`: Administrator terminal." 101 | Write-Host "$green_check`: Winget version 1.10.390 minimum." 102 | Write-Host "$green_check`: Microsoft Winget client installed." 103 | Write-Host "$green_check`: All pre-requisites complete. Proceeding with installation..." 104 | Start-Sleep 2 105 | return $true 106 | } 107 | } else { 108 | # Internal mode - install silently with error handling 109 | try { 110 | # Try to install NuGet package provider 111 | $nugetInstalled = Get-PackageProvider -Name NuGet -ErrorAction SilentlyContinue 112 | if (-not $nugetInstalled) { 113 | Write-Host "Installing NuGet package provider..." -ForegroundColor Yellow 114 | Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force -Scope CurrentUser -ErrorAction Stop 115 | } else { 116 | Write-Host "NuGet package provider already installed." -ForegroundColor Green 117 | } 118 | } catch { 119 | Write-Host "Warning: Could not install NuGet package provider. Continuing anyway..." -ForegroundColor Yellow 120 | Write-Host "Error: $($_.Exception.Message)" -ForegroundColor Red 121 | } 122 | 123 | try { 124 | # Try to install Microsoft.WinGet.Client module 125 | if (-not (Get-InstalledModule -Name "Microsoft.WinGet.Client" -ErrorAction SilentlyContinue)) { 126 | Write-Host "Installing Microsoft.WinGet.Client module..." -ForegroundColor Yellow 127 | Install-Module -Name Microsoft.WinGet.Client -Force -Scope CurrentUser -ErrorAction Stop 128 | } else { 129 | Write-Host "Microsoft.WinGet.Client module already installed." -ForegroundColor Green 130 | } 131 | } catch { 132 | Write-Host "Warning: Could not install Microsoft.WinGet.Client module. Continuing anyway..." -ForegroundColor Yellow 133 | Write-Host "Error: $($_.Exception.Message)" -ForegroundColor Red 134 | } 135 | 136 | try { 137 | # Try to upgrade winget 138 | Write-Host "Checking for winget updates..." -ForegroundColor Yellow 139 | winget upgrade winget --silent --disable-interactivity --accept-source-agreements 2>$null 140 | } catch { 141 | Write-Host "Warning: Could not upgrade winget. Continuing anyway..." -ForegroundColor Yellow 142 | } 143 | 144 | return $true 145 | } 146 | } -------------------------------------------------------------------------------- /.github/actions/scans/coverity/README.md: -------------------------------------------------------------------------------- 1 | # Coverity Scan with Community Credentials 2 | 3 | This GitHub Action installs a specific version of Coverity and performs a scan. 4 | 5 | ## Inputs 6 | 7 | - `project` (required): Project name in Coverity Scan. Default is `${{ github.repository }}`. 8 | - `token` (required): Secret project token for accessing Coverity Scan. 9 | - `email` (required): Where Coverity Scan should send notifications. 10 | - `build_language` (required): Which Coverity Scan language pack to download. Default is `other`. 11 | - `build_platform` (required): Which Coverity Scan platform pack to download. Default is `linux64`. 12 | - `command` (required): Command to pass to `cov-build`. Default is `make`. 13 | - `working-directory` (optional): Working directory to set for all steps. Default is `${{ github.workspace }}`. 14 | - `version` (required): (Informational) The source version being built. Default is `${{ github.sha }}`. 15 | - `description` (optional): (Informational) A description for this particular build. Default is `coverity-scan-action ${{ github.repository }} / ${{ github.ref }}`. 16 | - `report_name` (optional): The name of the report file. Default is `coverity-results`. 17 | - `upload_to_artifactory` (optional): Flag to control whether to upload to Artifactory. Default is `false`. 18 | - `run_coverity_scan` (optional): Flag to control whether to run the Coverity scan and upload to Artifactory. Default is `false`. 19 | 20 | ## Permissions 21 | 22 | This action requires read permissions for all available permissions. 23 | ```yaml 24 | permissions: read-all 25 | ``` 26 | 27 | ## Parameters 28 | 29 | ```yaml 30 | project: 31 | description: Project name in Coverity Scan. 32 | default: ${{ github.repository }} 33 | required: true 34 | token: 35 | description: Secret project token for accessing Coverity Scan. 36 | required: true 37 | email: 38 | description: Where Coverity Scan should send notifications. 39 | required: true 40 | build_language: 41 | description: Which Coverity Scan language pack to download. 42 | default: other 43 | required: true 44 | build_platform: 45 | description: Which Coverity Scan platform pack to download. 46 | default: linux64 47 | required: true 48 | command: 49 | description: Command to pass to cov-build. 50 | default: make 51 | required: true 52 | working-directory: 53 | description: Working directory to set for all steps. 54 | default: ${{ github.workspace }} 55 | required: false 56 | version: 57 | description: (Informational) The source version being built. 58 | default: ${{ github.sha }} 59 | required: true 60 | description: 61 | description: (Informational) A description for this particular build. 62 | default: coverity-scan-action ${{ github.repository }} / ${{ github.ref }} 63 | required: false 64 | report_name: 65 | description: 'Name of the report file' 66 | required: false 67 | default: 'coverity-results' 68 | upload_to_artifactory: 69 | description: 'Flag to control whether to upload to Artifactory' 70 | required: false 71 | default: 'false' 72 | run_coverity_scan: 73 | description: 'run coverity scan and also upload to artifactory' 74 | required: false 75 | default: 'false' 76 | ``` 77 | 78 | ## This step encodes the project name for use in URLs and HTTP forms. 79 | ```yaml 80 | - name: URL encode project name 81 | id: project 82 | run: echo "project=${{ inputs.project }}" | sed -e 's:/:%2F:g' -e 's/ /%20/g' >> $GITHUB_OUTPUT 83 | shell: bash 84 | ``` 85 | 86 | ## This step looks up the hash of the Coverity Build Tool to determine if there's been an update. 87 | ```yaml 88 | - name: Lookup Coverity Build Tool hash 89 | id: coverity-cache-lookup 90 | run: | 91 | hash=$(curl https://scan.coverity.com/download/${{ inputs.build_language }}/${{ inputs.build_platform }} \ 92 | --data "token=${TOKEN}&project=${{ steps.project.outputs.project }}&md5=1"); \ 93 | echo "hash=${hash}" >> $GITHUB_OUTPUT 94 | shell: bash 95 | env: 96 | TOKEN: ${{ inputs.token }} 97 | ``` 98 | 99 | ## This step caches the Coverity Build Tool to avoid downloading the archive on every run. 100 | ```yaml 101 | - name: Cache Coverity Build Tool 102 | id: cov-build-cache 103 | uses: actions/cache@v4 104 | with: 105 | path: ${{ inputs.working-directory }}/cov-analysis 106 | key: cov-build-${{ inputs.build_language }}-${{ inputs.build_platform }}-${{ steps.coverity-cache-lookup.outputs.hash }} 107 | ``` 108 | 109 | ## Downloads the Coverity Build Tool if it's not already cached. 110 | ```yaml 111 | - name: Download Coverity Build Tool (${{ inputs.build_language }} / ${{ inputs.build_platform }}) 112 | if: "steps.cov-build-cache.outputs.cache-hit != 'true'" 113 | run: | 114 | curl https://scan.coverity.com/download/${{ inputs.build_language }}/${{ inputs.build_platform }} \ 115 | --no-progress-meter \ 116 | --output cov-analysis.tar.gz \ 117 | --data "token=${TOKEN}&project=${{ steps.project.outputs.project }}" 118 | shell: bash 119 | working-directory: ${{ inputs.working-directory }} 120 | env: 121 | TOKEN: ${{ inputs.token }} 122 | ``` 123 | 124 | ## This step creates the `cov-analysis` directory if it's not already cached. 125 | ```yaml 126 | - if: steps.cov-build-cache.outputs.cache-hit != 'true' 127 | run: mkdir -p cov-analysis 128 | shell: bash 129 | working-directory: ${{ inputs.working-directory }} 130 | ``` 131 | 132 | ## This step extracts the Coverity Build Tool if it's not already cached. 133 | ```yaml 134 | - if: steps.cov-build-cache.outputs.cache-hit != 'true' 135 | run: tar -xzf cov-analysis.tar.gz --strip 1 -C cov-analysis 136 | shell: bash 137 | working-directory: ${{ inputs.working-directory }} 138 | ``` 139 | 140 | ## This step builds the project using `cov-build`. 141 | ```yaml 142 | - name: Build with cov-build 143 | run: | 144 | export PATH="${PWD}/cov-analysis/bin:${PATH}" 145 | cov-build --dir cov-int ${{ inputs.command }} --fs-capture-search-exclude-regex "cov-analysis" 146 | shell: bash 147 | working-directory: ${{ inputs.working-directory }} 148 | ``` 149 | 150 | ## This step archives the Coverity scan results. 151 | ```yaml 152 | - name: Archive results 153 | run: tar -czvf ${{ inputs.report_name }}.tgz cov-int 154 | shell: bash 155 | working-directory: ${{ inputs.working-directory }} 156 | ``` 157 | 158 | ## This step uploads the Coverity scan results to Artifactory if the corresponding flags are set. 159 | ```yaml 160 | - name: Upload Coverity Scan Results 161 | if: ${{ inputs.upload_to_artifactory == 'true' || inputs.run_coverity_scan == 'true'}} 162 | uses: actions/upload-artifact@v4 163 | with: 164 | name: ${{ inputs.report_name }} 165 | path: ${{ inputs.report_name }}.tgz 166 | ``` 167 | 168 | ## This step submits the Coverity scan results to Coverity Scan. 169 | ```yaml 170 | - name: Submit results to Coverity Scan 171 | run: | 172 | curl \ 173 | --form token="${TOKEN}" \ 174 | --form email="${{ inputs.email }}" \ 175 | --form file=@${{ inputs.report_name }}.tgz \ 176 | --form version="${{ inputs.version }}" \ 177 | --form description="${{ inputs.description }}" \ 178 | "https://scan.coverity.com/builds?project=${{ steps.project.outputs.project }}" 179 | shell: bash 180 | working-directory: ${{ inputs.working-directory }} 181 | env: 182 | TOKEN: ${{ inputs.token }} 183 | ``` -------------------------------------------------------------------------------- /Linux_Software_Installation/setup-software.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright (C) 2025 Intel Corporation 4 | # SPDX-License-Identifier: MIT License 5 | 6 | set -e 7 | 8 | # symbol 9 | S_VALID="✓" 10 | CURRENT_DIRECTORY=$(pwd) 11 | 12 | # verify current user 13 | if [ "$EUID" -eq 0 ]; then 14 | echo "Must not run with sudo or root user" 15 | exit 1 16 | fi 17 | 18 | install_packages(){ 19 | local PACKAGES=("$@") 20 | local INSTALL_REQUIRED=0 21 | for PACKAGE in "${PACKAGES[@]}"; do 22 | INSTALLED_VERSION=$(dpkg-query -W -f='${Version}' "$PACKAGE" 2>/dev/null || true) 23 | LATEST_VERSION=$(apt-cache policy "$PACKAGE" | grep Candidate | awk '{print $2}') 24 | 25 | if [ -z "$INSTALLED_VERSION" ] || [ "$INSTALLED_VERSION" != "$LATEST_VERSION" ]; then 26 | echo "$PACKAGE is not installed or not the latest version." 27 | INSTALL_REQUIRED=1 28 | fi 29 | done 30 | if [ $INSTALL_REQUIRED -eq 1 ]; then 31 | sudo -E apt update 32 | sudo -E apt install -y "${PACKAGES[@]}" 33 | fi 34 | } 35 | 36 | install_vulkan_sdk(){ 37 | echo -e "\n# Installing Vulkan SDK" 38 | # Add Vulkan repository key 39 | wget -qO- https://packages.lunarg.com/lunarg-signing-key-pub.asc | sudo tee /etc/apt/trusted.gpg.d/lunarg.asc 40 | 41 | # Add Vulkan repository for Ubuntu 24.04 (Noble) 42 | sudo wget -qO /etc/apt/sources.list.d/lunarg-vulkan-noble.list http://packages.lunarg.com/vulkan/lunarg-vulkan-noble.list 43 | 44 | # Update package list and install Vulkan SDK 45 | sudo apt update 46 | sudo apt install -y vulkan-sdk 47 | 48 | echo "$S_VALID Vulkan SDK installed" 49 | } 50 | 51 | verify_dependencies(){ 52 | echo -e "\n# Verifying dependencies" 53 | DEPENDENCIES_PACKAGES=( 54 | python3-pip 55 | python3-venv 56 | cmake 57 | build-essential 58 | pkg-config 59 | git 60 | curl 61 | wget 62 | ) 63 | install_packages "${DEPENDENCIES_PACKAGES[@]}" 64 | install_vulkan_sdk 65 | echo "$S_VALID Dependencies installed" 66 | } 67 | 68 | install_uv(){ 69 | echo -e "\n# Installing UV" 70 | if ! command -v uv &> /dev/null; then 71 | wget -qO- https://astral.sh/uv/install.sh | sh 72 | # Add UV to PATH for current session 73 | export PATH="$HOME/.local/bin:$PATH" 74 | # Verify installation 75 | if command -v uv &> /dev/null; then 76 | echo "$S_VALID UV installed successfully" 77 | else 78 | echo "Warning: UV installation may require a shell restart to update PATH" 79 | fi 80 | else 81 | echo "$S_VALID UV is already installed" 82 | fi 83 | } 84 | 85 | install_openvino_notebook(){ 86 | 87 | echo -e "\n# Git clone OpenVINO™ notebooks" 88 | if [ ! -d "./openvino_notebooks" ]; then 89 | cd ~/intel 90 | git clone https://github.com/openvinotoolkit/openvino_notebooks.git 91 | cd openvino_notebooks 92 | python3 -m venv venv 93 | source venv/bin/activate 94 | pip install -r requirements.txt 95 | # Create ipykernel for this environment 96 | pip install ipykernel 97 | python -m ipykernel install --user --name=openvino_notebooks --display-name="OpenVINO Notebooks" 98 | deactivate 99 | else 100 | echo "./openvino_notebooks already exists" 101 | fi 102 | echo -e "\n# Build OpenVINO™ notebook complete" 103 | } 104 | 105 | install_openvino_notebook2(){ 106 | 107 | echo -e "\n# Git clone OpenVINO™ notebooks 2" 108 | if [ ! -d "./openvino_build_deploy" ]; then 109 | cd ~/intel 110 | git clone https://github.com/openvinotoolkit/openvino_build_deploy.git 111 | cd openvino_build_deploy/workshops/MSBuild2025 112 | python3 -m venv venv 113 | source venv/bin/activate 114 | pip install openvino==2025.3.0 ultralytics==8.3.120 115 | # Create ipykernel for this environment 116 | pip install ipykernel 117 | python -m ipykernel install --user --name=openvino_build_deploy --display-name="OpenVINO Build Deploy" 118 | deactivate 119 | else 120 | echo "./openvino_build_deploy already exists" 121 | fi 122 | echo -e "\n# Build OpenVINO™ notebook2 complete" 123 | } 124 | 125 | install_openvino_genai(){ 126 | 127 | echo -e "\n# OpenVINO™ GenAI" 128 | if [ ! -d "./openvino_genai_ubuntu24_2025.3.0.0_x86_64" ]; then 129 | cd ~/intel 130 | 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 131 | tar -xf openvino_genai_2025.3.0.0.tgz 132 | 133 | cd openvino_genai_u* 134 | sudo -E ./install_dependencies/install_openvino_dependencies.sh 135 | source setupvars.sh 136 | cd samples/cpp 137 | ./build_samples.sh 138 | else 139 | echo "./openvino_genai_ubuntu24_2025.3.0.0_x86_64 already exists" 140 | fi 141 | echo -e "\n# Build OpenVINO™ GenAI complete" 142 | } 143 | 144 | install_llamacpp(){ 145 | echo -e "\n# Install llama.cpp with Vulkan support" 146 | 147 | cd ~/intel 148 | if [ ! -d "./llama.cpp" ]; then 149 | # Check Vulkan support 150 | echo "Checking Vulkan support..." 151 | vulkaninfo 152 | 153 | # Clone and build llama.cpp with Vulkan support 154 | git clone https://github.com/ggerganov/llama.cpp.git 155 | cd llama.cpp 156 | 157 | # Build with Vulkan support 158 | cmake -B build -DGGML_VULKAN=1 -DLLAMA_CURL=OFF 159 | cmake --build build --config Release 160 | 161 | echo "$S_VALID llama.cpp native built with Vulkan support" 162 | else 163 | echo "llama.cpp already exists" 164 | fi 165 | 166 | # Install llama-cpp-python with Vulkan support 167 | echo -e "\n# Installing llama-cpp-python with Vulkan support" 168 | if [ ! -d "./llamacpp_python_env" ]; then 169 | cd ~/intel 170 | python3 -m venv llamacpp_python_env 171 | source llamacpp_python_env/bin/activate 172 | 173 | # Set environment variable for Vulkan support 174 | export CMAKE_ARGS="-DGGML_VULKAN=ON -DLLAMA_CURL=OFF" 175 | pip install llama-cpp-python 176 | 177 | # Create ipykernel for this environment 178 | pip install ipykernel 179 | python -m ipykernel install --user --name=llamacpp_python --display-name="LlamaCPP Python (Vulkan)" 180 | deactivate 181 | echo "$S_VALID llama-cpp-python installed with Vulkan support" 182 | else 183 | echo "llamacpp_python_env already exists" 184 | fi 185 | 186 | echo -e "\n# llama.cpp installation complete" 187 | } 188 | 189 | install_ollama(){ 190 | 191 | echo -e "\n# Install Ollama (regular version)" 192 | cd ~/intel 193 | 194 | # Install regular Ollama using the official installer 195 | curl -fsSL https://ollama.com/install.sh | sh 196 | 197 | # Start Ollama service 198 | ollama serve & 199 | sleep 5 200 | 201 | # Pull a model for testing 202 | ollama pull llama3.2:1b 203 | 204 | echo -e "\n# Ollama install complete" 205 | } 206 | 207 | install_chrome(){ 208 | 209 | echo -e "\n# Install chrome" 210 | cd ~/intel 211 | wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb 212 | sudo apt -y install ./google-chrome-stable_current_amd64.deb 213 | echo -e "\n# chrome install complete" 214 | } 215 | 216 | install_other_notebooks(){ 217 | 218 | echo -e "\n# Git clone Other notebooks " 219 | if [ ! -d "./AI-PC-Samples" ]; then 220 | cd ~/intel 221 | git clone https://github.com/intel/AI-PC-Samples.git 222 | 223 | # Create virtual environment for AI-PC-Samples if it has requirements 224 | if [ -f "./AI-PC-Samples/AI-Travel-Agent/requirements.txt" ]; then 225 | cd AI-PC-Samples 226 | python3 -m venv venv 227 | source venv/bin/activate 228 | pip install -r AI-Travel-Agent/requirements.txt 229 | # Create ipykernel for this environment 230 | pip install ipykernel 231 | python -m ipykernel install --user --name=ai_pc_samples --display-name="AI PC Samples" 232 | deactivate 233 | cd .. 234 | fi 235 | else 236 | echo "./AI-PC-Samples already exists" 237 | fi 238 | echo -e "\n# Clone other notebooks complete" 239 | } 240 | 241 | install_vs_code(){ 242 | 243 | echo -e "\n# Install VS Code" 244 | wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > packages.microsoft.gpg 245 | sudo install -o root -g root -m 644 packages.microsoft.gpg /etc/apt/trusted.gpg.d/ 246 | 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' 247 | sudo apt update 248 | sudo apt install code 249 | echo -e "\n# VS Code complete" 250 | } 251 | 252 | setup() { 253 | if [ ! -d "/home/$(whoami)/intel" ]; then 254 | echo "Creating ~/intel directory" 255 | mkdir ~/intel 256 | else 257 | echo "~/intel already exists" 258 | fi 259 | cd ~/intel 260 | verify_dependencies 261 | install_uv 262 | install_openvino_notebook 263 | install_openvino_notebook2 264 | install_openvino_genai 265 | install_llamacpp 266 | install_ollama 267 | install_chrome 268 | install_other_notebooks 269 | install_vs_code 270 | 271 | echo -e "\n# Status" 272 | echo "$S_VALID AI PC DevKit Installed" 273 | echo -e "\nInstalled Jupyter kernels:" 274 | echo "- OpenVINO Notebooks" 275 | echo "- OpenVINO Build Deploy" 276 | echo "- LlamaCPP Python (Vulkan)" 277 | echo "- AI PC Samples (if AI-Travel-Agent/requirements.txt exists)" 278 | echo -e "\nTo list all available kernels, run: jupyter kernelspec list" 279 | 280 | echo -e "\n# Virtual Environment Activation Commands" 281 | echo "To activate each virtual environment, use the following commands:" 282 | echo "" 283 | echo "1. OpenVINO Notebooks:" 284 | echo " cd ~/intel/openvino_notebooks && source venv/bin/activate" 285 | echo "" 286 | echo "2. OpenVINO Build Deploy:" 287 | echo " cd ~/intel/openvino_build_deploy/workshops/MSBuild2025 && source venv/bin/activate" 288 | echo "" 289 | echo "3. LlamaCPP Python (Vulkan):" 290 | echo " cd ~/intel && source llamacpp_python_env/bin/activate" 291 | echo "" 292 | if [ -d "./AI-PC-Samples" ] && [ -f "./AI-PC-Samples/AI-Travel-Agent/requirements.txt" ]; then 293 | echo "4. AI PC Samples:" 294 | echo " cd ~/intel/AI-PC-Samples && source venv/bin/activate" 295 | echo "" 296 | fi 297 | echo "5. OpenVINO GenAI (setup environment variables):" 298 | echo " cd ~/intel/openvino_genai_u* && source setupvars.sh" 299 | echo "" 300 | echo "Note: To deactivate any virtual environment, simply run: deactivate" 301 | } 302 | 303 | setup 304 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AIPC Application Installer Version v2.0 2 | 3 | ## Introduction 4 | 5 | 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 6 | 7 | **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. 8 | 9 | **New in v2.0:** 10 | 11 | - **Interactive GUI Mode**: Windows Forms interface 12 | 13 | Integrated Install: Visual interface for for visual package selection and installation 14 | Integrated Uninstall: Visual interface for visual package uninstall of previously installed packages 15 | - **Enhanced JSON Structure**: Improved package descriptions with friendly names and summaries 16 | - **Advanced Exit Code Handling**: Robust error detection and handling for both install and uninstall operations 17 | - **Automatic Administrator Privileges**: Smart detection and elevation requests for all operations 18 | - **Real-time Package Tracking**: Automatic tracking of installed packages for future uninstallation 19 | - **Backward Compatibility**: Works with both new and legacy JSON formats 20 | 21 | ## Key Features 22 | 23 | ### Smart Package Management 24 | - **Automatic Tracking**: Installed packages are tracked for easy uninstallation 25 | - **Duplicate Prevention**: Won't install already installed packages 26 | - **Dependency Resolution**: Handles package dependencies automatically 27 | 28 | ### Enhanced User Experience 29 | - **Visual Interface**: Windows Forms GUI for easy interaction 30 | - **Detailed Feedback**: Clear success/failure messages with exit code information 31 | - **Error Recovery**: Graceful handling of various installation scenarios 32 | 33 | ### Robust Operation 34 | - **Exit Code Intelligence**: Recognizes various success/failure conditions 35 | - **Administrator Handling**: Automatic privilege detection and elevation 36 | - **Logging**: Comprehensive logging for troubleshooting 37 | 38 | 39 | For any assistance, please refer to the support documentation or contact our technical support team. 40 | 41 | ## Quick Start 42 | 43 | ### Pre-requisites 44 | - **Administrator Privileges**: The script will automatically check and request administrator privileges when needed 45 | - **PowerShell Execution Policy**: Set to Unrestricted (the script will guide you) 46 | - **Winget**: Must be installed with version 1.10.X or higher 47 | 48 | 49 | 50 | ### Step 1: Set Execution Policy 51 | ```powershell 52 | Set-ExecutionPolicy -ExecutionPolicy Unrestricted LocalMachine 53 | ``` 54 | 55 | ### Step 2: Run the First Setup Script 56 | Navigate to the following directory and run the initial environment setup script: 57 | ```powershell 58 | cd Windows_Software_Installation\WingetGUI_Installer 59 | .\Setup_1.ps1 gui #Install/Uninstall using GUI Mode 60 | .\Setup_1.ps1 install #Install using commandline 61 | .\Setup_1.ps1 uninstall #UnInstall using commandline 62 | ``` 63 | GUI Mode opens the Windows Forms interface for interactive package selection and installation/uninstallation. 64 | 65 | ### Step 3: Reboot the Machine 66 | After completing the environment setup, reboot your machine to ensure all changes take effect and new environments are recognized. 67 | 68 | ### Step 4: Run the Second Setup Script 69 | ```powershell 70 | cd Windows_Software_Installation\WingetGUI_Installer 71 | .\Setup_2.ps1 72 | ``` 73 | This will pull a number of repositories and build the necessary environments to execute the samples. 74 | 75 | ## Options Internal vs External 76 | 77 | Internal Mode 78 | 79 | - Silent Operation: In internal mode, the script runs silently in the background, automatically accepting all license agreements. 80 | Module Installation: Installs the PowerShell module WingetClient and updates winget to the latest version 1.10.390. 81 | 82 | External Mode 83 | -Silent Operation but with User Interaction: In external mode, users must manually accept pop-up agreements before utilizing the application. 84 | 85 | ## Pre-requisites to run script 86 | 87 | 88 | Administrator Privileges: Ensure the "powershell" terminal is running in admin mode. 89 | 90 | - Example `Set-ExecutionPolicy -ExecutionPolicy Unrestricted LocalMachine` 91 | 92 | - `winget` must be installed on computer with latest version 1.10.X or higher 93 | Winget Installation version verification use command: `winget --version` 94 | If not installed, execute 95 | Install-Module -Name Microsoft.WinGet.Client 96 | Repair-WinGetPackageManager -Force -Latest 97 | - Ensure you have the latest version `1.10.X` 98 | 99 | - 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` 100 | 101 | 102 | 103 | #### Global Install Flags 104 | 105 | - `global_install_flags` 106 | - These are run for `winget`. The pre included ones are: 107 | - `--silent` Allows it to run in the background 108 | - `--accept-package-agreements` and `--accept-source-agreements` Allows it to run via task scheduler without having UAC pop ups 109 | - `--disable-interactivity` Another fallback to remove UAC agreements 110 | - `--force` Final check to ensure things resolve and install 111 | 112 | ### Applications JSON Structure 113 | - **JSON Configuration**: [Windows_Software_Installation/WingetGUI_Installer/JSON/install/applications.json](./Windows_Software_Installation/WingetGUI_Installer/JSON/install/applications.json) 114 | 115 | Winget Applications 116 | Applications installed via the Windows package manager, with automatic dependency resolution: 117 | 118 | { 119 | 120 | 121 | "id": "Microsoft.VisualStudioCode", 122 | "friendly_name": "Visual Studio Code", 123 | "summary": "Code editor", 124 | "override_flags": null, 125 | "install_location": null, 126 | "version": null, 127 | "version_check": null, 128 | "dependencies": null, 129 | "skip_install": "no" 130 | } 131 | 132 | External Applications 133 | Applications not installed via the Windows package manager, requiring a URL for download via curl 134 | 135 | { 136 | "name": "one_api_base_toolkit", 137 | "source": "https://install_url/application.exe", 138 | "install_flags": "--some --exes --want --install --flags", 139 | "download_location": "C:\\Required\\download\\location", 140 | "uninstall_command": "C:\\Required\\download\\location\\uninstaller.exe", 141 | "dependencies": [ 142 | { 143 | "name": "Optional Dependency" 144 | }, 145 | { 146 | "name": "Visual Studio Code" 147 | }, 148 | { 149 | "name": "C++ Redistribution" 150 | } 151 | ] 152 | } 153 | 154 | Notes:- 155 | 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. 156 | 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: 157 | 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 158 | 159 | "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. 160 | 161 | To find the specific product version, execute: 162 | .\installer.exe --list-products 163 | 164 | #### Workflow Overview 165 | 166 | 1. Administrator Privileges Check: Verifies admin access. 167 | 2. Execution Policy Setting: Sets policy to Unrestricted. 168 | 3. Application List Reading: Reads from applications.json. 169 | 4. Log Directory Initialization: Prepares logging environment. 170 | 5. Application Identification: Determines applications for installation. 171 | 6. Installation and Logging: Installs applications and logs the process. 172 | 7. Uninstall JSON Creation: Generates a file for tracking installed applications. 173 | 174 | **Applications Configuration** 175 | 176 | **applications.json Overview** 177 | The applications.json file configures applications for installation by the Setup_1.ps1 script, detailing Winget and external applications along with their installation parameters. 178 | 179 | **VerifyInstall** 180 | 181 | 1. This script performs a basic command line version check with the specified tool. 182 | 183 | - Global Install Flags: Default flags for all installations. 184 | - Winget Applications: Array of Winget applications to be installed. 185 | - External Applications: Array of external applications to be installed. 186 | 187 | Adding New Applications to installer 188 | To add an application, first verify its availability via winget: 189 | Example: 190 | 191 | #### Overview 192 | 193 | - Reads application list from `applications.json` 194 | - Installs Winget applications and external applications 195 | - Logs installation process 196 | - Creates an uninstall JSON file for tracking installed applications 197 | 198 | #### Workflow 199 | 200 | 1. Checks for administrator privileges 201 | 2. Sets execution policy to Unrestricted 202 | 3. Reads application list from `applications.json` 203 | 4. Initializes log directory 204 | 5. Identifies applications that need to be installed 205 | 6. Installs each application and logs the process 206 | 7. Creates an uninstall JSON file for tracking installed applications 207 | 208 | ### applications.json 209 | 210 | #### Overview 211 | 212 | 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. 213 | 214 | #### VerifyInstall 215 | 216 | This script runs a basic command line version check with the specified tool 217 | 218 | ##### Root Object 219 | 220 | - `global_install_flags` (string): Default flags for all installations 221 | - `winget_applications` (array): List of Winget applications to be installed 222 | - `external_applications` (array): List of external applications to be installed 223 | 224 | ## Opens/Issues 225 | 226 | - 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. 227 | - 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 228 | 229 | ## Documentation 230 | 231 | For detailed documentation, configuration guides, and troubleshooting: 232 | - **Windows Installer Documentation**: [Windows_Software_Installation/README.md](./Windows_Software_Installation/README.md) 233 | 234 | ## Support 235 | 236 | For technical assistance, configuration help, or feature requests: 237 | - Contact: Ram (vaithi.s.ramadoss@intel.com) or Vijay (vijay.chandrashekar@intel.com) 238 | - Full documentation: [Windows_Software_Installation/README.md](./Windows_Software_Installation/README.md) 239 | -------------------------------------------------------------------------------- /Windows_Software_Installation/README.md: -------------------------------------------------------------------------------- 1 | # Windows Software Installation for AI PC Development 2 | 3 | Comprehensive tools for setting up AI PC development applications and environments on Windows, including GUI-based package management and automated repository downloaders. 4 | 5 | ## 🚀 Quick Start 6 | 7 | ### Prerequisites 8 | - Windows 11 with PowerShell 5.1 or PowerShell Core 9 | - Internet connection 10 | - Administrative privileges (required--will attempt to auto-elevate) 11 | 12 | ### ⚠️ Important: Execution Policy Requirements 13 | **This script must be run from an elevated PowerShell prompt.** 14 | 15 | If you encounter execution policy errors preventing scripts from running, use one of these methods: 16 | 17 | **Method 1 - Run with execution policy parameter (Recommended):** 18 | ```powershell 19 | # For GUI mode 20 | powershell.exe -ExecutionPolicy RemoteSigned -File ".\Setup_1.ps1" gui 21 | 22 | # For command line install 23 | powershell.exe -ExecutionPolicy RemoteSigned -File ".\Setup_1.ps1" install 24 | ``` 25 | 26 | ### Step 1: GUI Package Manager (Recommended) 27 | **Best for setting up complete AI development environments** 28 | ```powershell 29 | # Navigate to the installer directory 30 | cd "Windows_Software_Installation\WingetGUI_Installer" 31 | 32 | # Launch the unified GUI 33 | .\Setup_1.ps1 gui 34 | ``` 35 | 36 | ### Step 2: Download AI Repositories and create environments 37 | **Best for getting AI/ML code repositories** 38 | ```powershell 39 | # Navigate to the installer directory 40 | cd "Windows_Software_Installation\WingetGUI_Installer" 41 | 42 | # Run with default settings (downloads to C:\Intel) 43 | .\Setup_2.ps1 44 | 45 | # Or specify custom directory 46 | .\Setup_2.ps1 -DevKitWorkingDir "C:\MyAIProjects" 47 | ``` 48 | 49 | ### Option 3: Command Line Package Installation 50 | **Best for automated/scripted environments** 51 | ```powershell 52 | cd "Windows_Software_Installation\WingetGUI_Installer" 53 | 54 | # If execution policy allows scripts: 55 | .\Setup_1.ps1 install 56 | 57 | # If execution policy blocks scripts: 58 | powershell.exe -ExecutionPolicy RemoteSigned -File ".\Setup_1.ps1" install 59 | 60 | # Or uninstall 61 | .\Setup_1.ps1 uninstall 62 | ``` 63 | 64 | --- 65 | 66 | ## 🛠️ Available Tools 67 | 68 | ### 🎯 Winget GUI Installer 69 | **Modern graphical package manager for AI development tools** 70 | 71 | **Features:** 72 | - ✅ **Unified Interface**: Single GUI for install/uninstall operations 73 | - ✅ **AI Development Focus**: Curated package collections for AI/ML development 74 | - ✅ **Progress Tracking**: Real-time installation progress with detailed logging 75 | - ✅ **Smart Tracking**: Maintains history of installed packages for easy removal 76 | - ✅ **Bidirectional Compatibility**: Install via GUI or command line, uninstall via either method 77 | - ✅ **Error Handling**: Robust error reporting and retry mechanisms 78 | 79 | **Usage:** 80 | ```powershell 81 | # GUI Mode (Interactive) 82 | .\Setup_1.ps1 gui 83 | # Or if execution policy blocks: powershell.exe -ExecutionPolicy RemoteSigned -File ".\Setup_1.ps1" gui 84 | 85 | # Command Line Mode (Silent) 86 | .\Setup_1.ps1 install 87 | # Or if execution policy blocks: powershell.exe -ExecutionPolicy RemoteSigned -File ".\Setup_1.ps1" install 88 | 89 | # Uninstall Mode 90 | .\Setup_1.ps1 uninstall 91 | ``` 92 | 93 | ### 📦 Repository Downloader 94 | **Automated download and setup of AI/ML repositories** 95 | 96 | **Features:** 97 | - ✅ **Parallel Downloads**: Downloads up to 5 repositories simultaneously 98 | - ✅ **Retry Logic**: Automatic retry with exponential backoff (2s, 4s, 8s delays) 99 | - ✅ **Progress Tracking**: Real-time download progress and completion status 100 | - ✅ **Smart Skipping**: Skips existing directories and downloaded files 101 | - ✅ **Automatic Extraction**: Extracts ZIP files and organizes into proper directories 102 | - ✅ **Resume Capability**: Can be run multiple times safely 103 | 104 | **Current AI Repositories:** 105 | 1. **OpenVINO Notebooks** - Jupyter notebooks for OpenVINO toolkit 106 | 2. **OpenVINO Build & Deploy** - Build and deployment examples 107 | 3. **Ollama IPEX-LLM** - Ollama with Intel Extension for PyTorch 108 | 4. **OpenVINO GenAI** - Generative AI examples and tools 109 | 5. **WebNN Workshop** - Web Neural Network API workshop materials 110 | 6. **Open Model Zoo** - Pre-trained models collection 111 | 112 | --- 113 | 114 | ## 📋 Detailed Usage Guide 115 | 116 | ### Winget GUI Installer 117 | 118 | #### System Requirements 119 | - **Windows 10/11**: Windows PowerShell 5.1 or PowerShell 7+ 120 | - **Winget**: Windows Package Manager (installed by default on Windows 11) 121 | - **Internet Connection**: Required for package downloads 122 | - **Administrator Rights**: May be required for some package installations 123 | 124 | #### Step-by-Step Usage 125 | 126 | 1. **Verify Winget Installation**: 127 | ```powershell 128 | winget --version 129 | ``` 130 | Should show version 1.10.X or higher 131 | 132 | 2. **Launch GUI**: 133 | ```powershell 134 | cd "WingetGUI_Installer" 135 | 136 | # If execution policy allows scripts: 137 | .\Setup_1.ps1 gui 138 | 139 | # If execution policy blocks scripts: 140 | powershell.exe -ExecutionPolicy RemoteSigned -File ".\Setup_1.ps1" gui 141 | ``` 142 | 143 | 4. **Install Software**: 144 | - Click "Install Software" 145 | - Select desired packages from the list 146 | - Click "Install Selected" 147 | - Monitor real-time progress 148 | 149 | 5. **Uninstall Software**: 150 | - Click "Uninstall Software" 151 | - Select packages to remove 152 | - Confirm uninstallation 153 | - Tracking file automatically updated 154 | 155 | #### Package Categories 156 | - **Development Tools**: Git, Visual Studio Code, Visual Studio Community 157 | - **AI/ML Frameworks**: Python, CMake, Vulkan SDK, Intel oneAPI 158 | - **System Utilities**: Windows Terminal, PowerToys, Clink 159 | - **Developer Productivity**: Chrome, Firefox, various IDEs 160 | 161 | ### Repository Downloader 162 | 163 | #### Parameters 164 | | Parameter | Type | Default | Description | 165 | |-----------|------|---------|-------------| 166 | | `DevKitWorkingDir` | String | `C:\Intel` | Target directory for downloads | 167 | | `MaxRetries` | Integer | `3` | Maximum retry attempts per download | 168 | 169 | #### Directory Structure After Download 170 | ``` 171 | C:\Intel\ 172 | ├── openvino_notebooks\ 173 | ├── openvino_build_deploy\ 174 | ├── ollama-ipex-llm\ 175 | ├── openvino_genai\ 176 | ├── webnn_workshop\ 177 | └── open_model_zoo\ 178 | ``` 179 | 180 | #### Adding New Repositories 181 | 182 | 1. **Open `get_repos.ps1`** and locate the `$repos` array (around line 74) 183 | 2. **Add your repository**: 184 | ```powershell 185 | $repos = @( 186 | # ... existing repos ... 187 | @{ Name = "your_repo_name"; Uri = "https://github.com/owner/repo/archive/refs/heads/main.zip"; File = "repo.zip" } 188 | ) 189 | ``` 190 | 191 | 3. **Common URL Patterns**: 192 | - **Main Branch**: `https://github.com/owner/repo/archive/refs/heads/main.zip` 193 | - **Specific Branch**: `https://github.com/owner/repo/archive/refs/heads/branch-name.zip` 194 | - **Tagged Release**: `https://github.com/owner/repo/archive/refs/tags/v1.0.0.zip` 195 | - **Release Asset**: `https://github.com/owner/repo/releases/download/v1.0.0/filename.zip` 196 | 197 | --- 198 | 199 | ## 🔧 Advanced Configuration 200 | 201 | ### Winget Package Configuration 202 | 203 | The GUI installer uses JSON configuration files for package management: 204 | 205 | #### Adding Winget Applications 206 | ```json 207 | { 208 | "id": "Microsoft.VisualStudioCode", 209 | "friendly_name": "Visual Studio Code", 210 | "summary": "Code editor", 211 | "override_flags": null, 212 | "install_location": null, 213 | "version": null, 214 | "version_check": "code --version", 215 | "dependencies": null, 216 | "skip_install": "no" 217 | } 218 | ``` 219 | 220 | #### Adding External Applications 221 | ```json 222 | { 223 | "name": "custom_app", 224 | "friendly_name": "Custom Application", 225 | "summary": "Custom application description", 226 | "source": "https://download.url/installer.exe", 227 | "install_flags": "--silent --accept-eula", 228 | "download_location": ".\\Downloads\\CustomApp", 229 | "uninstall_command": "C:\\Path\\To\\uninstaller.exe --silent", 230 | "dependencies": [], 231 | "skip_install": "no" 232 | } 233 | ``` 234 | 235 | ### File Structure 236 | ``` 237 | Windows_Software_Installation/ 238 | ├── README.md # This file 239 | └── WingetGUI_Installer/ 240 | ├── README.md # GUI installer documentation 241 | ├── Setup_1.ps1 # Main installer script (GUI/CLI package manager) 242 | ├── Setup_2.ps1 # Repository downloader script 243 | ├── JSON/ 244 | │ ├── install/ 245 | │ │ └── applications.json # Package definitions 246 | │ └── uninstall/ 247 | │ └── uninstall.json # Installed package tracking 248 | ├── logs/ # Installation logs 249 | └── Public/ # Core functionality modules 250 | ├── GUI.ps1 # GUI interface 251 | ├── Install.ps1 # Installation functions 252 | ├── Uninstall.ps1 # Uninstallation functions 253 | ├── Append-ToJson.ps1 # JSON management 254 | └── Write_ToLog.ps1 # Logging utilities 255 | ``` 256 | 257 | --- 258 | 259 | ## 🛠️ Troubleshooting 260 | 261 | ### Common Issues 262 | 263 | #### Repository Downloader 264 | - **Download Failures**: Check internet connection and verify URLs are accessible 265 | - **Extraction Errors**: Ensure sufficient disk space and file permissions 266 | - **Permission Errors**: Run PowerShell as Administrator 267 | 268 | #### Winget GUI Installer 269 | - **"Package not found" during uninstall**: Package was already uninstalled by another method (system will recognize this as success) 270 | - **GUI doesn't show packages for uninstall**: No packages installed through this system yet 271 | - **Script hangs on startup**: Check for UAC dialog waiting for user response 272 | - **Installation shows as failed but package is installed**: Check logs for specific exit codes 273 | 274 | ### Exit Code Reference 275 | 276 | #### Installation Exit Codes 277 | - **0**: Successful installation 278 | - **-1978335212**: Already installed (treated as success) 279 | - **-1978335209**: Version not found (treated as failure) 280 | - **-1978335210**: Package not found (treated as failure) 281 | 282 | #### Uninstall Exit Codes 283 | - **0**: Successfully uninstalled 284 | - **1**: Package not found (treated as success - goal achieved) 285 | - **-1978335212**: Package not in installed list (treated as success) 286 | - **-1978335210**: Package not found (treated as success - goal achieved) 287 | 288 | ### Performance Notes 289 | - **Parallel Downloads**: Up to 5 simultaneous downloads for repositories 290 | - **Memory Usage**: ~1MB buffer per download stream 291 | - **Retry Strategy**: Exponential backoff (2s, 4s, 8s delays) 292 | - **Bidirectional Compatibility**: Install via any method, uninstall via any method 293 | 294 | --- 295 | 296 | ## 📞 Support 297 | 298 | For technical assistance or feature requests: 299 | 300 | - **Repository Issues**: Check individual repository documentation 301 | - **GUI Installer Issues**: Check logs in `WingetGUI_Installer\logs\` 302 | - **Feature Requests**: Contact development team 303 | 304 | ## 📄 License 305 | 306 | This script collection is provided as-is for Intel AI Dev Kit setup. Individual repositories and packages have their own licenses. 307 | -------------------------------------------------------------------------------- /Windows_Software_Installation/OVMS/ovms_setup.ps1: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env powershell 2 | <# 3 | .SYNOPSIS 4 | Simple One-Command OVMS Script - Download and Start Models (v2025.3 Compatible) 5 | 6 | .DESCRIPTION 7 | Downloads OVMS v2025.3, downloads models, and starts the server in one command. 8 | Supports GPU/CPU/NPU devices with automatic model selection and required task parameters. 9 | 10 | .PARAMETER Model 11 | Model type: "text" (default), "image", or full OpenVINO model name 12 | 13 | .PARAMETER Target 14 | Target device: "GPU" (default), "CPU", or "NPU" 15 | 16 | .PARAMETER Port 17 | REST API port (default: 8000) 18 | 19 | .EXAMPLE 20 | .\start_ovms_simple_v2025.3.ps1 21 | # Starts Phi-3 text model on GPU 22 | 23 | .EXAMPLE 24 | .\start_ovms_simple_v2025.3.ps1 -Target NPU 25 | # Starts NPU-optimized Phi-3 on NPU 26 | 27 | .EXAMPLE 28 | .\start_ovms_simple_v2025.3.ps1 -Model image 29 | # Starts FLUX image generation on GPU 30 | 31 | .EXAMPLE 32 | .\start_ovms_simple_v2025.3.ps1 -Model "OpenVINO/Mistral-7B-Instruct-v0.2-int4-cw-ov" -Target CPU 33 | # Starts custom model on CPU 34 | #> 35 | 36 | param( 37 | [string]$Model = "text", 38 | [ValidateSet("GPU", "CPU", "NPU")] 39 | [string]$Target = "GPU", 40 | [int]$Port = 8000, 41 | [switch]$Help 42 | ) 43 | 44 | # Color output functions 45 | function Write-Info { param([string]$Message) Write-Host "[INFO] $Message" -ForegroundColor Cyan } 46 | function Write-Success { param([string]$Message) Write-Host "[OK] $Message" -ForegroundColor Green } 47 | function Write-Warning { param([string]$Message) Write-Host "[WARN] $Message" -ForegroundColor Yellow } 48 | function Write-Error { param([string]$Message) Write-Host "[ERROR] $Message" -ForegroundColor Red } 49 | 50 | # Default models for each device 51 | $DefaultModels = @{ 52 | "GPU" = @{ 53 | "text" = "OpenVINO/Phi-3.5-mini-instruct-int4-ov" 54 | "image" = "OpenVINO/FLUX.1-schnell-int4-ov" 55 | } 56 | "CPU" = @{ 57 | "text" = "OpenVINO/Phi-3.5-mini-instruct-int4-ov" 58 | "image" = "OpenVINO/stable-diffusion-v1-5-int8-ov" 59 | } 60 | "NPU" = @{ 61 | "text" = "OpenVINO/Phi-3.5-mini-instruct-int4-cw-ov" 62 | "image" = "OpenVINO/FLUX.1-schnell-int8-ov" 63 | } 64 | } 65 | 66 | function Get-SourceModel { 67 | param([string]$ModelInput, [string]$TargetDevice) 68 | 69 | # If it's a shorthand, resolve to full model name 70 | if ($ModelInput -eq "text" -or $ModelInput -eq "image") { 71 | return $DefaultModels[$TargetDevice][$ModelInput] 72 | } 73 | 74 | # If it's already a full model name, return as-is 75 | return $ModelInput 76 | } 77 | 78 | function Get-ModelTask { 79 | param([string]$SourceModel) 80 | 81 | # Determine task type based on model name patterns 82 | $imageModelPatterns = @( 83 | "*FLUX*", 84 | "*flux*", 85 | "*diffusion*", 86 | "*Dreamshaper*", 87 | "*SDXL*", 88 | "*stable-diffusion*", 89 | "*controlnet*", 90 | "*text-to-image*", 91 | "*image-generation*" 92 | ) 93 | 94 | foreach ($pattern in $imageModelPatterns) { 95 | if ($SourceModel -like $pattern) { 96 | return "image_generation" 97 | } 98 | } 99 | 100 | # Default to text generation for all other models 101 | return "text_generation" 102 | } 103 | 104 | function Initialize-OVMS { 105 | Write-Info "Setting up OVMS..." 106 | 107 | $ovmsDir = "ovms" 108 | $ovmsExe = Join-Path $ovmsDir "ovms.exe" 109 | 110 | if (Test-Path $ovmsExe) { 111 | Write-Success "OVMS already available" 112 | 113 | # Always run setupvars to ensure environment is properly initialized 114 | $setupVars = Join-Path $ovmsDir "setupvars.ps1" 115 | if (Test-Path $setupVars) { 116 | Write-Info "Initializing OpenVINO Model Server environment..." 117 | try { 118 | $setupOutput = & $setupVars 2>&1 119 | if ($setupOutput -like "*Environment Initialized*") { 120 | Write-Success "OpenVINO Model Server Environment Initialized" 121 | } else { 122 | Write-Info "Environment setup completed" 123 | } 124 | } 125 | catch { 126 | Write-Warning "Environment setup had issues, but continuing..." 127 | } 128 | } 129 | 130 | return $ovmsExe 131 | } 132 | 133 | Write-Info "Downloading OVMS v2025.3...." 134 | $ovmsUrl = "https://github.com/openvinotoolkit/model_server/releases/download/v2025.3/ovms_windows_python_on.zip" 135 | $ovmsZip = "ovms.zip" 136 | 137 | try { 138 | Invoke-WebRequest -Uri $ovmsUrl -OutFile $ovmsZip -UseBasicParsing 139 | Expand-Archive -Path $ovmsZip -DestinationPath "." -Force 140 | Remove-Item $ovmsZip -Force -ErrorAction SilentlyContinue 141 | 142 | if (Test-Path $ovmsExe) { 143 | Write-Success "OVMS downloaded and extracted" 144 | 145 | # Run setupvars to initialize environment 146 | $setupVars = Join-Path $ovmsDir "setupvars.ps1" 147 | if (Test-Path $setupVars) { 148 | Write-Info "Initializing OpenVINO Model Server environment..." 149 | try { 150 | $setupOutput = & $setupVars 2>&1 151 | if ($setupOutput -like "*Environment Initialized*") { 152 | Write-Success "OpenVINO Model Server Environment Initialized" 153 | } else { 154 | Write-Info "Environment setup completed" 155 | } 156 | } 157 | catch { 158 | Write-Warning "Environment setup had issues, but continuing..." 159 | } 160 | } 161 | 162 | return $ovmsExe 163 | } else { 164 | throw "OVMS extraction failed" 165 | } 166 | } 167 | catch { 168 | Write-Error "Failed to setup OVMS: $_" 169 | exit 1 170 | } 171 | } 172 | 173 | function Start-OVMSServer { 174 | param([string]$SourceModel, [string]$TargetDevice, [int]$RestPort) 175 | 176 | Write-Info "Starting OVMS Server..." 177 | Write-Info "Model: $SourceModel" 178 | Write-Info "Target: $TargetDevice" 179 | Write-Info "Port: $RestPort" 180 | Write-Success "API will be available at: http://localhost:$RestPort/v3" 181 | Write-Info "" 182 | 183 | # Ensure models directory exists 184 | if (-not (Test-Path "models")) { 185 | New-Item -ItemType Directory -Path "models" -Force | Out-Null 186 | } 187 | 188 | # Determine the task type for the model 189 | $taskType = Get-ModelTask -SourceModel $SourceModel 190 | 191 | Write-Info "Detected task type: $taskType" 192 | Write-Info "Starting server (model will download automatically if not cached)..." 193 | Write-Warning "Press Ctrl+C to stop the server" 194 | Write-Info "" 195 | 196 | try { 197 | if ($taskType -eq "image_generation") { 198 | Write-Info "Using image generation mode with --task image_generation..." 199 | & ".\ovms\ovms.exe" --rest_port $RestPort --model_repository_path "models" --task image_generation --source_model $SourceModel --target_device $TargetDevice --log_level INFO 200 | } else { 201 | Write-Info "Using text generation mode with --task text_generation..." 202 | & ".\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 203 | } 204 | } 205 | catch { 206 | Write-Error "Failed to start OVMS server: $_" 207 | exit 1 208 | } 209 | } 210 | 211 | # Main execution 212 | Write-Info "Simple OVMS Launcher (v2025.3 Compatible)" 213 | Write-Info "==========================================" 214 | 215 | # Show help if requested 216 | if ($Help) { 217 | Write-Host "" 218 | Write-Host "Simple OVMS Launcher - One Command Setup (v2025.3 Compatible)" -ForegroundColor Yellow 219 | Write-Host "=============================================================" -ForegroundColor Yellow 220 | Write-Host "" 221 | Write-Host "USAGE:" -ForegroundColor Green 222 | Write-Host " .\start_ovms_simple_v2025.3.ps1 [-Model ] [-Target ] [-Port ]" -ForegroundColor White 223 | Write-Host "" 224 | Write-Host "PARAMETERS:" -ForegroundColor Green 225 | Write-Host " -Model : 'text' (default), 'image', or full OpenVINO model name" -ForegroundColor White 226 | Write-Host " -Target : 'GPU' (default), 'CPU', or 'NPU'" -ForegroundColor White 227 | Write-Host " -Port : REST API port (default: 8000)" -ForegroundColor White 228 | Write-Host " -Help : Show this help message" -ForegroundColor White 229 | Write-Host "" 230 | Write-Host "NEW IN v2025.3:" -ForegroundColor Green 231 | Write-Host " • Automatic task detection (--task text_generation or --task image_generation)" -ForegroundColor White 232 | Write-Host " • Enhanced model pattern recognition for task assignment" -ForegroundColor White 233 | Write-Host " • Required task parameters for all model types" -ForegroundColor White 234 | Write-Host "" 235 | Write-Host "EXAMPLES:" -ForegroundColor Green 236 | Write-Host " .\start_ovms_simple_v2025.3.ps1" -ForegroundColor Cyan 237 | Write-Host " # Start Phi-3 text model on GPU with --task text_generation" -ForegroundColor Gray 238 | Write-Host "" 239 | Write-Host " .\start_ovms_simple_v2025.3.ps1 -Target CPU" -ForegroundColor Cyan 240 | Write-Host " # Start Phi-3 text model on CPU with --task text_generation" -ForegroundColor Gray 241 | Write-Host "" 242 | Write-Host " .\start_ovms_simple_v2025.3.ps1 -Target NPU" -ForegroundColor Cyan 243 | Write-Host " # Start NPU-optimized Phi-3 on NPU with --task text_generation" -ForegroundColor Gray 244 | Write-Host "" 245 | Write-Host " .\start_ovms_simple_v2025.3.ps1 -Model image" -ForegroundColor Cyan 246 | Write-Host " # Start FLUX image generation on GPU with --task image_generation" -ForegroundColor Gray 247 | Write-Host "" 248 | Write-Host " .\start_ovms_simple_v2025.3.ps1 -Model 'OpenVINO/Mistral-7B-Instruct-v0.2-int4-cw-ov' -Target NPU" -ForegroundColor Cyan 249 | Write-Host " # Start custom Mistral model on NPU with --task text_generation" -ForegroundColor Gray 250 | Write-Host "" 251 | Write-Host "DEFAULT MODELS:" -ForegroundColor Green 252 | Write-Host " Text (GPU/CPU): OpenVINO/Phi-3.5-mini-instruct-int4-ov" -ForegroundColor White 253 | Write-Host " Text (NPU): OpenVINO/Phi-3.5-mini-instruct-int4-cw-ov" -ForegroundColor White 254 | Write-Host " Image (GPU): OpenVINO/FLUX.1-schnell-int4-ov" -ForegroundColor White 255 | Write-Host " Image (CPU): OpenVINO/stable-diffusion-v1-5-int8-ov" -ForegroundColor White 256 | Write-Host " Image (NPU): OpenVINO/FLUX.1-schnell-int8-ov" -ForegroundColor White 257 | Write-Host "" 258 | Write-Host "TASK AUTO-DETECTION:" -ForegroundColor Green 259 | Write-Host " Image models (--task image_generation): *FLUX*, *diffusion*, *SDXL*, etc." -ForegroundColor White 260 | Write-Host " Text models (--task text_generation): All other models (Phi-3, Mistral, etc.)" -ForegroundColor White 261 | Write-Host "" 262 | Write-Host "BUILT-IN HELP:" -ForegroundColor Green 263 | Write-Host " Get-Help .\start_ovms_simple_v2025.3.ps1" -ForegroundColor Cyan 264 | Write-Host " Get-Help .\start_ovms_simple_v2025.3.ps1 -Examples" -ForegroundColor Cyan 265 | Write-Host " Get-Help .\start_ovms_simple_v2025.3.ps1 -Detailed" -ForegroundColor Cyan 266 | Write-Host "" 267 | Write-Host "API ACCESS:" -ForegroundColor Green 268 | Write-Host " Once started, API available at: http://localhost:/v3" -ForegroundColor White 269 | Write-Host "" 270 | return 271 | } 272 | 273 | # Setup OVMS if needed 274 | $ovmsExe = Initialize-OVMS 275 | 276 | # Resolve model name 277 | $sourceModel = Get-SourceModel -ModelInput $Model -TargetDevice $Target 278 | 279 | if (-not $sourceModel) { 280 | Write-Error "Invalid model/target combination" 281 | Write-Info "Available models:" 282 | Write-Info " text - Text generation (Phi-3.5)" 283 | Write-Info " image - Image generation (FLUX/Stable Diffusion)" 284 | Write-Info " Or provide full OpenVINO model name" 285 | exit 1 286 | } 287 | 288 | # Start the server 289 | Start-OVMSServer -SourceModel $sourceModel -TargetDevice $Target -RestPort $Port 290 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL Advanced" 13 | 14 | on: 15 | workflow_dispatch: 16 | push: 17 | branches: [ "main" ] 18 | schedule: 19 | - cron: '25 0 * * 2' 20 | 21 | permissions: 22 | contents: read 23 | 24 | jobs: 25 | analyze: 26 | name: Analyze (${{ matrix.language }}) 27 | # Runner size impacts CodeQL analysis time. To learn more, please see: 28 | # - https://gh.io/recommended-hardware-resources-for-running-codeql 29 | # - https://gh.io/supported-runners-and-hardware-resources 30 | # - https://gh.io/using-larger-runners (GitHub.com only) 31 | # Consider using larger runners or machines with greater resources for possible analysis time improvements. 32 | runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} 33 | permissions: 34 | # required for all workflows 35 | security-events: write 36 | 37 | # required to fetch internal or private CodeQL packs 38 | packages: read 39 | 40 | # only required for workflows in private repositories 41 | actions: read 42 | contents: read 43 | 44 | strategy: 45 | fail-fast: false 46 | matrix: 47 | include: 48 | - language: javascript-typescript 49 | build-mode: none 50 | # Commented out languages that don't exist in this repository 51 | # - language: python 52 | # build-mode: none 53 | # - language: csharp 54 | # build-mode: autobuild 55 | # CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' 56 | # javascript-typescript provides some basic analysis for shell scripts (.sh) and can analyze any .js/.ts files 57 | # Re-enable python when you add actual .py source code files 58 | # Re-enable csharp when you add actual C# projects (.csproj, .sln files) 59 | # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis, 60 | # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning. 61 | # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how 62 | # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages 63 | steps: 64 | - name: Harden Runner 65 | uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 66 | with: 67 | egress-policy: audit 68 | 69 | - name: Checkout repository 70 | uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 71 | 72 | # Initializes the CodeQL tools for scanning. 73 | - name: Initialize CodeQL 74 | uses: github/codeql-action/init@294a9d92911152fe08befb9ec03e240add280cb3 # v3.26.8 75 | with: 76 | languages: ${{ matrix.language }} 77 | build-mode: ${{ matrix.build-mode }} 78 | # If you wish to specify custom queries, you can do so here or in a config file. 79 | # By default, queries listed here will override any specified in a config file. 80 | # Prefix the list here with "+" to use these queries and those in the config file. 81 | 82 | # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 83 | queries: security-extended,security-and-quality 84 | 85 | # If the analyze step fails for one of the languages you are analyzing with 86 | # "We were unable to automatically build your code", modify the matrix above 87 | # to set the build mode to "manual" for that language. Then modify this step 88 | # to build your code. 89 | # ℹ️ Command-line programs to run using the OS shell. 90 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 91 | - if: matrix.build-mode == 'manual' 92 | shell: bash 93 | run: | 94 | echo 'If you are using a "manual" build mode for one or more of the' \ 95 | 'languages you are analyzing, replace this with the commands to build' \ 96 | 'your code, for example:' 97 | echo ' make bootstrap' 98 | echo ' make release' 99 | exit 1 100 | 101 | - name: Perform CodeQL Analysis 102 | uses: github/codeql-action/analyze@294a9d92911152fe08befb9ec03e240add280cb3 # v3.26.8 103 | with: 104 | category: "/language:${{matrix.language}}" 105 | 106 | # Generate security report only after analysis completes 107 | - name: Generate Security Report 108 | if: matrix.language == 'javascript-typescript' # Run only once, not for each language 109 | uses: rsdmike/github-security-report-action@a149b24539044c92786ec39af8ba38c93496495d # v3.0.4 110 | with: 111 | template: report 112 | token: ${{ secrets.AIPC_SDK_TOKEN }} 113 | 114 | - name: GitHub Upload Release Artifacts 115 | if: matrix.language == 'javascript-typescript' # Upload only once, not for each language 116 | uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 117 | with: 118 | name: report 119 | path: | 120 | ./report.pdf 121 | 122 | # Trivy security scanning - additional security layer 123 | trivy-scan: 124 | name: Trivy Security Scan 125 | runs-on: ubuntu-latest 126 | permissions: 127 | contents: read 128 | security-events: write 129 | 130 | steps: 131 | - name: Harden Runner 132 | uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 133 | with: 134 | egress-policy: audit 135 | 136 | - name: Checkout code 137 | uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 138 | 139 | # List dependency files for debugging 140 | - name: List dependency files for scanning 141 | run: | 142 | echo "## 📋 Dependency Files Found" >> $GITHUB_STEP_SUMMARY 143 | echo "" >> $GITHUB_STEP_SUMMARY 144 | echo "### Python Requirements Files:" >> $GITHUB_STEP_SUMMARY 145 | find . -name "requirements.txt" -type f | while read file; do 146 | echo "- \`$file\`" >> $GITHUB_STEP_SUMMARY 147 | echo " - Dependencies: $(grep -v '^#' "$file" | grep -v '^$' | wc -l)" >> $GITHUB_STEP_SUMMARY 148 | done 149 | echo "" >> $GITHUB_STEP_SUMMARY 150 | echo "### Other Package Files:" >> $GITHUB_STEP_SUMMARY 151 | find . -name "package.json" -o -name "Gemfile" -o -name "go.mod" -o -name "composer.json" -o -name "Cargo.toml" | while read file; do 152 | echo "- \`$file\`" >> $GITHUB_STEP_SUMMARY 153 | done || echo "- No additional package files found" >> $GITHUB_STEP_SUMMARY 154 | echo "" >> $GITHUB_STEP_SUMMARY 155 | 156 | # Vulnerability scanning 157 | - name: Run Trivy vulnerability scanner 158 | uses: aquasecurity/trivy-action@915b19bbe73b92a6cf82a1bc12b087c9a19a5fe2 # v0.28.0 159 | with: 160 | scan-type: 'fs' 161 | scan-ref: '.' 162 | ignore-unfixed: true 163 | format: 'sarif' 164 | output: 'trivy-vuln-results.sarif' 165 | severity: 'CRITICAL,HIGH,MEDIUM,LOW,UNKNOWN' 166 | scanners: 'vuln' 167 | # Ensure scanning of Python requirements files 168 | scan-all-unpackaged: true 169 | 170 | # Secret scanning 171 | - name: Run Trivy secret scanner 172 | uses: aquasecurity/trivy-action@915b19bbe73b92a6cf82a1bc12b087c9a19a5fe2 # v0.28.0 173 | with: 174 | scan-type: 'fs' 175 | scan-ref: '.' 176 | format: 'sarif' 177 | output: 'trivy-secret-results.sarif' 178 | scanners: 'secret' 179 | 180 | # Configuration scanning 181 | - name: Run Trivy configuration scanner 182 | uses: aquasecurity/trivy-action@915b19bbe73b92a6cf82a1bc12b087c9a19a5fe2 # v0.28.0 183 | with: 184 | scan-type: 'fs' 185 | scan-ref: '.' 186 | format: 'sarif' 187 | output: 'trivy-config-results.sarif' 188 | scanners: 'config' 189 | 190 | # Upload all Trivy results to GitHub Security tab 191 | - name: Upload vulnerability results 192 | uses: github/codeql-action/upload-sarif@294a9d92911152fe08befb9ec03e240add280cb3 # v3.26.8 193 | if: always() 194 | with: 195 | sarif_file: 'trivy-vuln-results.sarif' 196 | category: 'trivy-vulnerabilities' 197 | 198 | - name: Upload secret scan results 199 | uses: github/codeql-action/upload-sarif@294a9d92911152fe08befb9ec03e240add280cb3 # v3.26.8 200 | if: always() 201 | with: 202 | sarif_file: 'trivy-secret-results.sarif' 203 | category: 'trivy-secrets' 204 | 205 | - name: Upload configuration scan results 206 | uses: github/codeql-action/upload-sarif@294a9d92911152fe08befb9ec03e240add280cb3 # v3.26.8 207 | if: always() 208 | with: 209 | sarif_file: 'trivy-config-results.sarif' 210 | category: 'trivy-configurations' 211 | 212 | # Generate human-readable Trivy report 213 | - name: Generate Trivy comprehensive report 214 | uses: aquasecurity/trivy-action@915b19bbe73b92a6cf82a1bc12b087c9a19a5fe2 # v0.28.0 215 | with: 216 | scan-type: 'fs' 217 | scan-ref: '.' 218 | format: 'table' 219 | output: 'trivy-report.txt' 220 | severity: 'CRITICAL,HIGH,MEDIUM,LOW,UNKNOWN' 221 | scanners: 'vuln,secret,config' 222 | scan-all-unpackaged: true 223 | 224 | # Generate detailed JSON report for debugging 225 | - name: Generate Trivy detailed JSON report 226 | uses: aquasecurity/trivy-action@915b19bbe73b92a6cf82a1bc12b087c9a19a5fe2 # v0.28.0 227 | with: 228 | scan-type: 'fs' 229 | scan-ref: '.' 230 | format: 'json' 231 | output: 'trivy-detailed.json' 232 | severity: 'CRITICAL,HIGH,MEDIUM,LOW,UNKNOWN' 233 | scanners: 'vuln,secret,config' 234 | scan-all-unpackaged: true 235 | 236 | # Upload Trivy reports 237 | - name: Upload Trivy comprehensive reports 238 | uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 239 | if: always() 240 | with: 241 | name: trivy-comprehensive-report 242 | path: | 243 | trivy-*.sarif 244 | trivy-report.txt 245 | trivy-detailed.json 246 | retention-days: 30 247 | 248 | # Add summary step to show scan results 249 | - name: Display Trivy scan summary 250 | if: always() 251 | run: | 252 | echo "## 🛡️ Trivy Security Scan Results" >> $GITHUB_STEP_SUMMARY 253 | echo "" >> $GITHUB_STEP_SUMMARY 254 | 255 | # Check if vulnerabilities were found 256 | if [ -s trivy-vuln-results.sarif ]; then 257 | echo "### 🔍 Vulnerability Scan" >> $GITHUB_STEP_SUMMARY 258 | vuln_count=$(jq '.runs[0].results | length' trivy-vuln-results.sarif) 259 | if [ "$vuln_count" -gt 0 ]; then 260 | echo "- ⚠️ Found $vuln_count vulnerabilities" >> $GITHUB_STEP_SUMMARY 261 | else 262 | echo "- ✅ No vulnerabilities found" >> $GITHUB_STEP_SUMMARY 263 | fi 264 | fi 265 | 266 | # Check if secrets were found 267 | if [ -s trivy-secret-results.sarif ]; then 268 | echo "### 🔐 Secret Scan" >> $GITHUB_STEP_SUMMARY 269 | secret_count=$(jq '.runs[0].results | length' trivy-secret-results.sarif) 270 | if [ "$secret_count" -gt 0 ]; then 271 | echo "- ⚠️ Found $secret_count potential secrets" >> $GITHUB_STEP_SUMMARY 272 | else 273 | echo "- ✅ No secrets detected" >> $GITHUB_STEP_SUMMARY 274 | fi 275 | fi 276 | 277 | # Check if config issues were found 278 | if [ -s trivy-config-results.sarif ]; then 279 | echo "### ⚙️ Configuration Scan" >> $GITHUB_STEP_SUMMARY 280 | config_count=$(jq '.runs[0].results | length' trivy-config-results.sarif) 281 | if [ "$config_count" -gt 0 ]; then 282 | echo "- ⚠️ Found $config_count configuration issues" >> $GITHUB_STEP_SUMMARY 283 | else 284 | echo "- ✅ No configuration issues found" >> $GITHUB_STEP_SUMMARY 285 | fi 286 | fi 287 | 288 | echo "" >> $GITHUB_STEP_SUMMARY 289 | echo "📊 **Detailed reports available in artifacts**" >> $GITHUB_STEP_SUMMARY 290 | echo "📁 Files scanned: $(find . -name '*.py' -o -name '*.js' -o -name '*.ts' -o -name 'requirements.txt' -o -name 'package.json' | wc -l) dependency/source files" >> $GITHUB_STEP_SUMMARY 291 | -------------------------------------------------------------------------------- /Linux_Software_Installation/Utilities/compatibility_check.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Intel Driver Version Compatibility Checker 4 | # This script checks for version compatibility between Intel Graphics Compiler (IGC) 5 | # and Intel Compute Runtime packages to prevent dependency conflicts 6 | 7 | set -e 8 | 9 | # Colors for output 10 | RED='\033[0;31m' 11 | GREEN='\033[0;32m' 12 | YELLOW='\033[1;33m' 13 | BLUE='\033[0;34m' 14 | NC='\033[0m' # No Color 15 | 16 | echo_info() { 17 | echo -e "${GREEN}[INFO]${NC} $1" 18 | } 19 | 20 | echo_warn() { 21 | echo -e "${YELLOW}[WARN]${NC} $1" 22 | } 23 | 24 | echo_error() { 25 | echo -e "${RED}[ERROR]${NC} $1" 26 | } 27 | 28 | echo_debug() { 29 | echo -e "${BLUE}[DEBUG]${NC} $1" 30 | } 31 | 32 | # Check GitHub token status 33 | if [ -n "$GITHUB_TOKEN" ]; then 34 | echo_info "GitHub token configured (${#GITHUB_TOKEN} characters)" 35 | AUTH_HEADER="Authorization: token $GITHUB_TOKEN" 36 | else 37 | echo_warn "No GitHub token found - may hit rate limits" 38 | echo_warn "Set GITHUB_TOKEN for better reliability" 39 | AUTH_HEADER="" 40 | fi 41 | 42 | # Function to get latest release tag 43 | get_latest_release_tag() { 44 | local repo="$1" 45 | echo_debug "Getting latest release for $repo..." 46 | 47 | local response 48 | if [ -n "$GITHUB_TOKEN" ]; then 49 | response=$(curl -s -H "$AUTH_HEADER" "https://api.github.com/repos/$repo/releases/latest" 2>/dev/null) 50 | else 51 | response=$(curl -s "https://api.github.com/repos/$repo/releases/latest" 2>/dev/null) 52 | fi 53 | 54 | # Check if curl failed or returned empty response 55 | if [ -z "$response" ]; then 56 | echo_error "Failed to connect to GitHub API for $repo" 57 | return 1 58 | fi 59 | 60 | # Check if response is valid JSON and contains tag_name 61 | if ! echo "$response" | jq -e '.tag_name' >/dev/null 2>&1; then 62 | echo_error "Invalid response from GitHub API for $repo" 63 | return 1 64 | fi 65 | 66 | local tag=$(echo "$response" | jq -r '.tag_name') 67 | if [ "$tag" = "null" ] || [ -z "$tag" ]; then 68 | echo_error "Could not extract tag_name from response for $repo" 69 | return 1 70 | fi 71 | 72 | echo "$tag" 73 | return 0 74 | } 75 | 76 | # Function to find compatible IGC version for compute runtime 77 | find_compatible_igc_version() { 78 | local compute_runtime_tag="$1" 79 | echo_info "Finding compatible IGC version for compute runtime $compute_runtime_tag..." 80 | 81 | # Get the compute runtime release assets 82 | local response 83 | if [ -n "$GITHUB_TOKEN" ]; then 84 | response=$(curl -s -H "$AUTH_HEADER" "https://api.github.com/repos/intel/compute-runtime/releases/tags/$compute_runtime_tag") 85 | else 86 | response=$(curl -s "https://api.github.com/repos/intel/compute-runtime/releases/tags/$compute_runtime_tag") 87 | fi 88 | 89 | # Look for intel-opencl-icd package 90 | local opencl_icd_url=$(echo "$response" | jq -r '.assets[] | select(.name | contains("intel-opencl-icd_")) | .browser_download_url' | head -1) 91 | 92 | if [ -n "$opencl_icd_url" ] && [ "$opencl_icd_url" != "null" ]; then 93 | echo_debug "Downloading intel-opencl-icd package to check dependencies..." 94 | 95 | # Download the package temporarily 96 | local temp_dir=$(mktemp -d) 97 | cd "$temp_dir" 98 | 99 | if wget -q "$opencl_icd_url" -O opencl-icd.deb 2>/dev/null; then 100 | # Extract control information 101 | local deps_info=$(dpkg-deb --info opencl-icd.deb 2>/dev/null | grep -A 20 "Depends:" || echo "No dependencies found") 102 | 103 | # Look for IGC dependency 104 | local igc_version=$(echo "$deps_info" | grep -o "intel-igc-opencl-2 (= [^)]*)" | sed 's/intel-igc-opencl-2 (= \([^)]*\))/\1/' | head -1) 105 | 106 | cd - > /dev/null 107 | rm -rf "$temp_dir" 108 | 109 | if [ -n "$igc_version" ]; then 110 | echo_info "Found required IGC version: $igc_version" 111 | echo "$igc_version" 112 | return 0 113 | fi 114 | fi 115 | 116 | cd - > /dev/null 117 | rm -rf "$temp_dir" 118 | fi 119 | 120 | echo_error "Could not determine compatible IGC version" 121 | return 1 122 | } 123 | 124 | # Function to find IGC release tag for a specific version 125 | find_igc_tag_for_version() { 126 | local target_version="$1" 127 | echo_debug "Searching for IGC tag matching version $target_version..." 128 | 129 | # Get IGC releases to find matching tag 130 | local response 131 | if [ -n "$GITHUB_TOKEN" ]; then 132 | response=$(curl -s -H "$AUTH_HEADER" "https://api.github.com/repos/intel/intel-graphics-compiler/releases?per_page=30") 133 | else 134 | response=$(curl -s "https://api.github.com/repos/intel/intel-graphics-compiler/releases?per_page=30") 135 | fi 136 | 137 | # Look through releases for matching version 138 | local matching_tag=$(echo "$response" | jq -r --arg version "$target_version" '.[] | select(.assets[].name | contains($version)) | .tag_name' | head -1) 139 | 140 | if [ -n "$matching_tag" ] && [ "$matching_tag" != "null" ]; then 141 | echo_info "Found matching IGC tag: $matching_tag" 142 | echo "$matching_tag" 143 | return 0 144 | fi 145 | 146 | echo_warn "Could not find IGC tag for version $target_version" 147 | 148 | # Try alternative approach - look for tags that might contain the version 149 | local alternative_tag=$(echo "$response" | jq -r '.[] | .tag_name' | grep -E "v?${target_version}" | head -1) 150 | 151 | if [ -n "$alternative_tag" ]; then 152 | echo_info "Found alternative IGC tag: $alternative_tag" 153 | echo "$alternative_tag" 154 | return 0 155 | fi 156 | 157 | return 1 158 | } 159 | 160 | # Function to check version compatibility 161 | check_version_compatibility() { 162 | local igc_tag="$1" 163 | local compute_runtime_tag="$2" 164 | 165 | echo_info "Checking compatibility between IGC $igc_tag and Compute Runtime $compute_runtime_tag..." 166 | 167 | # Create temp directory 168 | local temp_dir=$(mktemp -d) 169 | cd "$temp_dir" 170 | 171 | # Download a sample IGC package to check version 172 | local igc_response 173 | if [ -n "$GITHUB_TOKEN" ]; then 174 | igc_response=$(curl -s -H "$AUTH_HEADER" "https://api.github.com/repos/intel/intel-graphics-compiler/releases/tags/$igc_tag") 175 | else 176 | igc_response=$(curl -s "https://api.github.com/repos/intel/intel-graphics-compiler/releases/tags/$igc_tag") 177 | fi 178 | 179 | local igc_package_url=$(echo "$igc_response" | jq -r '.assets[] | select(.name | contains("intel-igc-opencl-2_")) | .browser_download_url' | head -1) 180 | 181 | # Download a sample Compute Runtime package 182 | local cr_response 183 | if [ -n "$GITHUB_TOKEN" ]; then 184 | cr_response=$(curl -s -H "$AUTH_HEADER" "https://api.github.com/repos/intel/compute-runtime/releases/tags/$compute_runtime_tag") 185 | else 186 | cr_response=$(curl -s "https://api.github.com/repos/intel/compute-runtime/releases/tags/$compute_runtime_tag") 187 | fi 188 | 189 | local cr_package_url=$(echo "$cr_response" | jq -r '.assets[] | select(.name | contains("intel-opencl-icd_")) | .browser_download_url' | head -1) 190 | 191 | if [ -n "$igc_package_url" ] && [ "$igc_package_url" != "null" ] && [ -n "$cr_package_url" ] && [ "$cr_package_url" != "null" ]; then 192 | echo_debug "Downloading packages to check compatibility..." 193 | 194 | if wget -q "$igc_package_url" -O igc.deb 2>/dev/null && wget -q "$cr_package_url" -O cr.deb 2>/dev/null; then 195 | # Extract IGC version from package 196 | local igc_version=$(dpkg-deb --field igc.deb Version 2>/dev/null | cut -d'+' -f1) 197 | 198 | # Extract required IGC version from compute runtime dependencies 199 | 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) 200 | 201 | cd - > /dev/null 202 | rm -rf "$temp_dir" 203 | 204 | if [ -n "$igc_version" ] && [ -n "$required_igc" ]; then 205 | echo_info "IGC package version: $igc_version" 206 | echo_info "Required IGC version: $required_igc" 207 | 208 | if [ "$igc_version" = "$required_igc" ]; then 209 | echo_info "✅ Versions are compatible!" 210 | return 0 211 | else 212 | echo_error "❌ Version mismatch detected!" 213 | echo_error " IGC provides: $igc_version" 214 | echo_error " Runtime needs: $required_igc" 215 | return 1 216 | fi 217 | fi 218 | fi 219 | fi 220 | 221 | cd - > /dev/null 222 | rm -rf "$temp_dir" 223 | echo_warn "Could not determine compatibility" 224 | return 1 225 | } 226 | 227 | # Function to collect compatible versions 228 | collect_compatible_versions() { 229 | echo_info "=== Collecting Compatible Driver Versions ===" 230 | echo 231 | 232 | # First, get the latest compute runtime version 233 | echo_info "Getting latest compute runtime version..." 234 | local compute_runtime_tag=$(get_latest_release_tag "intel/compute-runtime") 235 | if [ $? -ne 0 ]; then 236 | echo_error "Failed to get compute runtime version" 237 | return 1 238 | fi 239 | echo_info "Latest compute runtime: $compute_runtime_tag" 240 | 241 | # Find compatible IGC version 242 | local compatible_igc_version=$(find_compatible_igc_version "$compute_runtime_tag") 243 | if [ $? -ne 0 ]; then 244 | echo_warn "Could not determine compatible IGC version, using latest..." 245 | IGC_TAG=$(get_latest_release_tag "intel/intel-graphics-compiler") 246 | else 247 | IGC_TAG=$(find_igc_tag_for_version "$compatible_igc_version") 248 | if [ $? -ne 0 ]; then 249 | echo_warn "Could not find IGC tag for version $compatible_igc_version, using latest..." 250 | IGC_TAG=$(get_latest_release_tag "intel/intel-graphics-compiler") 251 | fi 252 | fi 253 | 254 | # Get other component versions 255 | COMPUTE_RUNTIME_TAG="$compute_runtime_tag" 256 | NPU_DRIVER_TAG=$(get_latest_release_tag "intel/linux-npu-driver") 257 | LEVEL_ZERO_TAG=$(get_latest_release_tag "oneapi-src/level-zero") 258 | 259 | echo 260 | echo_info "=== Selected Versions ===" 261 | echo_info "IGC: $IGC_TAG" 262 | echo_info "Compute Runtime: $COMPUTE_RUNTIME_TAG" 263 | echo_info "NPU Driver: $NPU_DRIVER_TAG" 264 | echo_info "Level Zero: $LEVEL_ZERO_TAG" 265 | echo 266 | 267 | # Verify compatibility 268 | echo_info "=== Verifying Compatibility ===" 269 | if check_version_compatibility "$IGC_TAG" "$COMPUTE_RUNTIME_TAG"; then 270 | echo_info "✅ All versions are compatible!" 271 | return 0 272 | else 273 | echo_error "❌ Version compatibility issues detected!" 274 | return 1 275 | fi 276 | } 277 | 278 | # Function to show usage 279 | show_usage() { 280 | cat << EOF 281 | Usage: $0 [options] 282 | 283 | Options: 284 | --check Check compatibility of current latest versions 285 | --igc-tag Check specific IGC tag compatibility 286 | --runtime-tag Check specific Compute Runtime tag compatibility 287 | --help Show this help message 288 | 289 | Examples: 290 | $0 --check # Check latest versions 291 | $0 --igc-tag v2.14.1 --runtime-tag 25.22.33944.8 # Check specific versions 292 | 293 | Environment Variables: 294 | GITHUB_TOKEN GitHub personal access token (recommended) 295 | EOF 296 | } 297 | 298 | # Main execution 299 | main() { 300 | local check_latest=false 301 | local igc_tag="" 302 | local runtime_tag="" 303 | 304 | # Parse command line arguments 305 | while [[ $# -gt 0 ]]; do 306 | case $1 in 307 | --check) 308 | check_latest=true 309 | shift 310 | ;; 311 | --igc-tag) 312 | igc_tag="$2" 313 | shift 2 314 | ;; 315 | --runtime-tag) 316 | runtime_tag="$2" 317 | shift 2 318 | ;; 319 | --help) 320 | show_usage 321 | exit 0 322 | ;; 323 | *) 324 | echo_error "Unknown option: $1" 325 | show_usage 326 | exit 1 327 | ;; 328 | esac 329 | done 330 | 331 | # Check for required tools 332 | if ! command -v jq &> /dev/null; then 333 | echo_error "jq is required but not installed. Install with: sudo apt install jq" 334 | exit 1 335 | fi 336 | 337 | if ! command -v curl &> /dev/null; then 338 | echo_error "curl is required but not installed. Install with: sudo apt install curl" 339 | exit 1 340 | fi 341 | 342 | echo_info "Intel Driver Version Compatibility Checker" 343 | echo_info "==========================================" 344 | echo 345 | 346 | if [ "$check_latest" = true ]; then 347 | # Check compatibility of latest versions 348 | if collect_compatible_versions; then 349 | echo 350 | echo_info "✅ Compatibility check passed!" 351 | echo_info "These versions can be used together safely." 352 | exit 0 353 | else 354 | echo 355 | echo_error "❌ Compatibility issues found!" 356 | echo_error "Using these versions together may cause dependency conflicts." 357 | exit 1 358 | fi 359 | elif [ -n "$igc_tag" ] && [ -n "$runtime_tag" ]; then 360 | # Check specific version compatibility 361 | echo_info "Checking specific versions:" 362 | echo_info "IGC: $igc_tag" 363 | echo_info "Compute Runtime: $runtime_tag" 364 | echo 365 | 366 | if check_version_compatibility "$igc_tag" "$runtime_tag"; then 367 | echo 368 | echo_info "✅ These versions are compatible!" 369 | exit 0 370 | else 371 | echo 372 | echo_error "❌ These versions are NOT compatible!" 373 | echo_error "This combination will cause dependency conflicts." 374 | exit 1 375 | fi 376 | else 377 | echo_error "No action specified. Use --check or provide specific versions." 378 | echo 379 | show_usage 380 | exit 1 381 | fi 382 | } 383 | 384 | # Run main function with all arguments 385 | main "$@" 386 | -------------------------------------------------------------------------------- /Linux_Software_Installation/README.md: -------------------------------------------------------------------------------- 1 | # Intel AI PC Linux Setup Guide 2 | 3 | Complete guide for setting up Intel AI PC development on Linux, including driver installation and AI software environment setup. 4 | 5 | --- 6 | 7 | ## 🔧 Part 1: Driver Setup (Required First) 8 | 9 | > **⚠️ CRITICAL: Install Drivers Before AI Software** 10 | > 11 | > 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. 12 | 13 | ### Overview 14 | 15 | 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. 16 | 17 | **Available Scripts:** 18 | - **`build-static-installer.sh`**: ⭐ Static installer builder (no GitHub token required) 19 | - **`setup-static-drivers.sh`**: Generated static driver installation script (no API dependencies) 20 | - **`Utilities/verify_connectivity.sh`**: Diagnostic tools for troubleshooting GitHub API connectivity issues 21 | 22 | ### Driver Installation Steps 23 | 24 | #### Step 1: Build and Run Static Installer ⭐ 25 | 26 | **No GitHub token required** 27 | 28 | ```bash 29 | # Navigate to driver setup directory 30 | cd Linux_Driver_Setup 31 | 32 | # Step 1: Build static installer with compatibility checking 33 | ./build-static-installer.sh --build-static 34 | 35 | # Step 2: Run the generated static installer 36 | sudo ./setup-static-drivers.sh 37 | ``` 38 | 39 | ## Troubleshooting 40 | 41 | 42 | #### GitHub API Rate Limiting 43 | **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. 44 | **Solution**: Set GITHUB_TOKEN environment variable 45 | ```bash 46 | export GITHUB_TOKEN=your_token_here 47 | sudo -E ./setup-static-drivers.sh # -E preserves environment variables 48 | ``` 49 | 50 | #### Network Connectivity 51 | **Problem**: Cannot reach GitHub 52 | **Solution**: Check your internet connection and firewall settings 53 | ```bash 54 | # Test basic connectivity 55 | curl https://github.com 56 | 57 | # Run full diagnostic 58 | ./verify_connectivity.sh 59 | ``` 60 | 61 | #### Permission Issues 62 | **Problem**: Script fails due to insufficient privileges 63 | **Solution**: Run with sudo 64 | ```bash 65 | sudo ./setup-static-drivers.sh 66 | ``` 67 | 68 | ### Diagnostic Script Output 69 | 70 | The `verify_connectivity.sh` script performs these checks: 71 | 72 | 1. **HTTPS Connectivity**: Tests connection to github.com 73 | 2. **GitHub API Access**: Verifies API accessibility and rate limits 74 | 3. **Repository Testing**: Checks latest versions for all required repositories: 75 | - intel/intel-graphics-compiler 76 | - intel/compute-runtime 77 | - intel/linux-npu-driver 78 | - oneapi-src/level-zero 79 | 80 | #### Successful Output Example 81 | 82 | ```text 83 | === Simple Driver Version Test === 84 | 85 | 1. Testing HTTPS connectivity... 86 | ✓ Can reach github.com via HTTPS 87 | 2. Testing GitHub API... 88 | Using GitHub authentication token 89 | ✓ GitHub API is accessible 90 | 91 | 3. Testing specific repositories... 92 | 93 | Testing intel/intel-graphics-compiler: 94 | ✓ Found version: v2.12.5 95 | 96 | Testing intel/compute-runtime: 97 | ✓ Found version: 25.22.33944.8 98 | 99 | Testing intel/linux-npu-driver: 100 | ✓ Found version: v1.17.0 101 | 102 | Testing oneapi-src/level-zero: 103 | ✓ Found version: v1.22.4 104 | 105 | Test completed! 106 | ``` 107 | 108 | #### Rate Limited Output Example 109 | 110 | ```text 111 | === Simple Driver Version Test === 112 | 113 | 1. Testing HTTPS connectivity... 114 | ✓ Can reach github.com via HTTPS 115 | 2. Testing GitHub API... 116 | ✗ GitHub API rate limit exceeded 117 | 118 | To fix this issue: 119 | 1. Set your GitHub token: export GITHUB_TOKEN=your_token_here 120 | 2. Get a token at: https://github.com/settings/tokens 121 | 3. Re-run this script 122 | ``` 123 | 124 | 125 | ### Updating Static Installers 126 | 127 | To update to newer driver versions: 128 | 129 | ```bash 130 | # Regenerate with latest versions 131 | ./build-static-installer.sh --build-static 132 | 133 | # The static installer will be updated with new URLs 134 | sudo ./setup-static-drivers.sh 135 | ``` 136 | 137 | ### Environment Variables 138 | 139 | - **`GITHUB_TOKEN`**: Personal access token for GitHub API (recommended) 140 | - **`OS_ID`**: Target OS identifier (default: "ubuntu") 141 | - **`OS_VERSION`**: Target OS version (default: "24.04") 142 | 143 | ### Manual Package Selection 144 | 145 | The script automatically downloads the latest versions, but you can check what versions would be installed: 146 | 147 | ```bash 148 | ./Utilities/verify_connectivity.sh 149 | ``` 150 | 151 | --- 152 | 153 | ## 🚀 Part 2: Software Setup (After Driver Installation) 154 | 155 | > **⚠️ IMPORTANT: Driver Setup Required First** 156 | > **⚠️ IMPORTANT: After installing drivers reboot the system before continuing to part 2.** 157 | > 158 | > 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. 159 | 160 | ### Overview 161 | 162 | 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. 163 | 164 | ### What This Script Installs 165 | 166 | #### Core Development Tools 167 | 168 | - **UV Package Manager**: Fast Python package manager for efficient dependency management 169 | - **Python Virtual Environments**: Proper isolation for AI projects 170 | - **Google Chrome**: Browser for web-based AI applications and Jupyter notebooks 171 | - **Visual Studio Code**: Popular IDE with AI development extensions 172 | 173 | #### AI/ML Frameworks and Toolkits 174 | 175 | - **OpenVINO Toolkit**: Intel's AI inference optimization framework 176 | - **OpenVINO GenAI**: Generative AI toolkit with Intel optimizations 177 | - **Ollama**: Local LLM runtime with Intel GPU acceleration 178 | 179 | #### Notebooks and Workshop Materials 180 | 181 | - **OpenVINO Notebooks**: Comprehensive collection of AI inference examples and tutorials 182 | - **MSBuild 2025 Workshop**: Latest Intel AI PC development workshop materials 183 | - **Additional Workshop Repositories**: Extra learning materials and sample projects 184 | 185 | #### Target Installation Directory 186 | 187 | All AI development materials are installed under `~/intel/` for organized project management. 188 | 189 | ### Software Installation Steps 190 | 191 | #### Prerequisites 192 | 193 | - **Operating System**: Ubuntu 24.04 LTS (recommended) 194 | - **Hardware**: Intel AI PC with compatible GPU and NPU 195 | - **Drivers**: Intel GPU/NPU drivers installed (Part 1 above) 196 | - **Memory**: At least 16GB RAM (32GB+ recommended for large models) 197 | - **Storage**: At least 10GB free space for all components 198 | 199 | #### Installation Commands 200 | 201 | ```bash 202 | # Navigate to software setup directory 203 | cd ../Linux_Software_Installation 204 | 205 | # Make the script executable 206 | chmod +x setup-software.sh 207 | 208 | # Run the setup (DO NOT use sudo) 209 | ./setup-software.sh 210 | ``` 211 | 212 | **Important Notes:** 213 | - **Never run with sudo**: The script explicitly prevents running as root for security 214 | - **Interactive Installation**: Some components may require user input during installation 215 | - **Time Requirements**: Full installation may take 30-60 minutes depending on internet speed 216 | - **Resumability**: Script checks for existing installations and can be re-run safely 217 | 218 | ### Installation Process 219 | 220 | #### Phase 1: System Preparation 221 | 222 | 1. Verifies user permissions (prevents sudo execution) 223 | 2. Checks and installs system dependencies 224 | 3. Creates the `~/intel` working directory 225 | 4. Sets up error handling and logging 226 | 227 | #### Phase 2: Python Environment Setup 228 | 229 | 1. Installs UV package manager for fast Python package management 230 | 2. Verifies Python 3 and pip installation 231 | 3. Sets up virtual environment capabilities 232 | 233 | #### Phase 3: AI Framework Installation 234 | 235 | 1. **OpenVINO Notebooks**: Clones and sets up the comprehensive notebook collection 236 | 2. **MSBuild 2025 Workshop**: Installs latest Intel AI PC workshop materials 237 | 3. **OpenVINO GenAI**: Sets up generative AI toolkit with Intel optimizations 238 | 4. **Ollama**: Installs local LLM runtime with Intel GPU acceleration 239 | 240 | #### Phase 4: Development Tools 241 | 242 | 1. **Google Chrome**: Installs browser for web-based development 243 | 2. **VS Code**: Installs popular IDE for AI development 244 | 3. **Additional Repositories**: Clones supplementary workshop materials 245 | 246 | ### What Gets Installed Where 247 | 248 | ```text 249 | ~/intel/ 250 | ├── openvino_notebooks/ # Main OpenVINO tutorial notebooks 251 | ├── MSBuild2025_NeuralChat/ # MSBuild 2025 workshop materials 252 | ├── openvino.genai/ # OpenVINO GenAI toolkit 253 | ├── WorkShops_BootCamp/ # Additional workshop materials 254 | ├── llm-on-ray/ # LLM on Ray examples 255 | └── various Python virtual environments 256 | ``` 257 | 258 | **System-wide Installations:** 259 | - **Ollama**: Installed system-wide via official installer 260 | - **Google Chrome**: Installed via .deb package 261 | - **VS Code**: Installed via official repository 262 | - **UV**: Installed system-wide Python package manager 263 | 264 | ### Post-Installation 265 | 266 | #### Verification Steps 267 | 268 | After installation completes, verify your setup: 269 | 270 | ```bash 271 | # Check Ollama installation 272 | ollama --version 273 | 274 | # Check UV installation 275 | uv --version 276 | 277 | # Check Chrome installation 278 | google-chrome --version 279 | 280 | # Check VS Code installation 281 | code --version 282 | 283 | # Verify Python environments 284 | ls ~/intel/*/venv/ 285 | ``` 286 | 287 | #### Getting Started 288 | 289 | 1. **Navigate to notebooks**: `cd ~/intel/openvino_notebooks` 290 | 2. **Activate environment**: `source venv/bin/activate` 291 | 3. **Start Jupyter**: `jupyter lab` 292 | 4. **Browse examples**: Explore the notebooks directory for AI examples 293 | 294 | #### Testing Ollama 295 | 296 | ```bash 297 | # Test Ollama with a simple model 298 | ollama pull llama2:7b 299 | ollama run llama2:7b "Hello, how are you?" 300 | ``` 301 | 302 | --- 303 | 304 | ## 🛠️ Comprehensive Troubleshooting 305 | 306 | ### Driver Issues 307 | 308 | #### GitHub API Rate Limiting 309 | **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. 310 | 311 | **Solution**: Set GITHUB_TOKEN environment variable 312 | ```bash 313 | export GITHUB_TOKEN=your_token_here 314 | sudo -E ./setup-static-drivers.sh # -E preserves environment variables 315 | ``` 316 | 317 | #### Network Connectivity 318 | **Problem**: Cannot reach GitHub 319 | 320 | **Solution**: Check your internet connection and firewall settings 321 | ```bash 322 | # Test basic connectivity 323 | curl https://github.com 324 | 325 | # Run full diagnostic (from Linux_Driver_Setup directory) 326 | ./Utilities/verify_connectivity.sh 327 | ``` 328 | 329 | #### Permission Issues 330 | **Problem**: Script fails due to insufficient privileges 331 | 332 | **Solution**: Run with sudo (drivers only) 333 | ```bash 334 | sudo ./setup-static-drivers.sh 335 | ``` 336 | 337 | ### Software Installation Issues 338 | 339 | #### Permission Errors 340 | 341 | - **Problem**: "Permission denied" errors during software installation 342 | - **Solution**: Ensure you're not running with sudo and have write access to home directory 343 | 344 | #### Network Timeouts 345 | 346 | - **Problem**: Downloads fail due to network issues 347 | - **Solution**: Check internet connection and re-run the script (it will skip completed installations) 348 | 349 | #### Python Environment Issues 350 | 351 | - **Problem**: Virtual environment creation fails 352 | - **Solution**: Ensure python3-venv is installed: `sudo apt install python3-venv` 353 | 354 | #### Disk Space Issues 355 | 356 | - **Problem**: Installation fails due to insufficient space 357 | - **Solution**: Free up at least 10GB of space and re-run 358 | 359 | #### GPU/NPU Recognition Issues 360 | 361 | - **Problem**: AI acceleration not working 362 | - **Solution**: Verify drivers are properly installed using the diagnostic script 363 | 364 | ### Log Files 365 | 366 | Installation logs are written to the terminal. For debugging: 367 | 368 | 1. Re-run the script with verbose output: `bash -x setup-software.sh` 369 | 2. Check individual component logs in their respective directories 370 | 371 | --- 372 | 373 | ## 📚 Advanced Configuration 374 | 375 | ### Updating Components 376 | 377 | #### Driver Updates 378 | 379 | To update to newer driver versions: 380 | 381 | ```bash 382 | cd Linux_Driver_Setup 383 | 384 | # Regenerate with latest versions 385 | ./build-static-installer.sh --build-static 386 | 387 | # The static installer will be updated with new URLs 388 | sudo ./setup-static-drivers.sh 389 | ``` 390 | 391 | #### Software Updates 392 | 393 | - **Ollama models**: `ollama pull ` 394 | - **OpenVINO notebooks**: `cd ~/intel/openvino_notebooks && git pull` 395 | - **VS Code**: Updates automatically or via system package manager 396 | - **Chrome**: Updates automatically 397 | 398 | ### Environment Variables 399 | 400 | #### Driver Setup Variables 401 | 402 | - **`GITHUB_TOKEN`**: Personal access token for GitHub API (recommended) 403 | - **`OS_ID`**: Target OS identifier (default: "ubuntu") 404 | - **`OS_VERSION`**: Target OS version (default: "24.04") 405 | 406 | #### Software Setup Variables 407 | 408 | - `HOME`: User home directory (used for ~/intel path) 409 | - `PATH`: Updated with new tool locations 410 | 411 | ### Customizing Installation 412 | 413 | The software script can be modified to skip certain components by commenting out function calls in the main execution section. 414 | 415 | ### Removing Components 416 | 417 | To clean up the software installation: 418 | 419 | ```bash 420 | # Remove all AI development materials 421 | rm -rf ~/intel/ 422 | 423 | # Uninstall system packages (optional) 424 | sudo apt remove google-chrome-stable code ollama 425 | ``` 426 | 427 | --- 428 | 429 | ## 📞 Support and Resources 430 | 431 | - **Intel AI PC Documentation**: [Intel Developer Zone](https://www.intel.com/content/www/us/en/developer/topic-technology/artificial-intelligence/overview.html) 432 | - **OpenVINO Documentation**: [OpenVINO Toolkit](https://docs.openvino.ai/) 433 | - **Issues**: Report problems via the project repository 434 | 435 | ## 📄 Security Considerations 436 | 437 | - Driver scripts run with sudo for necessary system-level installations 438 | - Software script prevents execution as root to avoid system-wide permission issues 439 | - Downloads from official sources only (GitHub, official package repositories) 440 | - Creates isolated Python environments to prevent dependency conflicts 441 | - No modification of system-critical directories or configurations 442 | 443 | ## Contributing 444 | 445 | When contributing to this project: 446 | 447 | 1. Test changes with the diagnostic script first 448 | 2. Ensure compatibility with Ubuntu 24.04 449 | 3. Update documentation for any new features 450 | 4. Follow the existing error handling patterns 451 | 452 | --- 453 | 454 | *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).* 455 | 456 | -------------------------------------------------------------------------------- /Windows_Software_Installation/WingetGUI_Installer/Public/Install.ps1: -------------------------------------------------------------------------------- 1 | # Install a list of selected packages (winget and external) 2 | function Install-SelectedPackages { 3 | param ( 4 | [Parameter(Mandatory=$true)] 5 | [array]$selectedPackages, 6 | [Parameter(Mandatory=$true)] 7 | [string]$log_file, 8 | [Parameter(Mandatory=$true)] 9 | [string]$uninstall_json_file 10 | ) 11 | 12 | # Ensure execution policy allows script execution 13 | try { 14 | $currentPolicy = Get-ExecutionPolicy -Scope CurrentUser 15 | if ($currentPolicy -eq "Restricted" -or $currentPolicy -eq "AllSigned") { 16 | Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser -Force 17 | Write-Host "Updated execution policy from $currentPolicy to RemoteSigned for CurrentUser" -ForegroundColor Yellow 18 | Write-ToLog -message "Updated execution policy from $currentPolicy to RemoteSigned for CurrentUser" -log_file $log_file 19 | } 20 | } 21 | catch { 22 | Write-Host "Warning: Could not set execution policy: $_" -ForegroundColor Yellow 23 | Write-ToLog -message "Warning: Could not set execution policy: $_" -log_file $log_file 24 | } 25 | 26 | $results = @() 27 | $installedCount = 0 28 | $failedCount = 0 29 | $skippedCount = 0 30 | $failedPackages = @() 31 | # Reload the original JSON so we can merge in all properties (like override_flags) 32 | $jsonPath = Join-Path (Split-Path $PSScriptRoot -Parent) 'JSON/install/applications.json' 33 | $allAppsJson = Get-Content -Path $jsonPath -Raw | ConvertFrom-Json 34 | $allWingetApps = $allAppsJson.winget_applications 35 | 36 | foreach ($app in $selectedPackages) { 37 | # Try to find the full app object from the original JSON by id 38 | $fullApp = $null 39 | if ($app.PSObject.Properties["id"]) { 40 | $fullApp = $allWingetApps | Where-Object { $_.id -eq $app.id } 41 | } elseif ($app.PSObject.Properties["name"]) { 42 | $fullApp = $allWingetApps | Where-Object { $_.id -eq $app.name } 43 | } 44 | if ($fullApp) { 45 | # Merge missing properties from fullApp into $app 46 | foreach ($prop in $fullApp.PSObject.Properties) { 47 | if (-not $app.PSObject.Properties[$prop.Name]) { 48 | $app | Add-Member -NotePropertyName $prop.Name -NotePropertyValue $prop.Value 49 | } 50 | } 51 | } 52 | $appType = if ($app.PSObject.Properties["id"]) { "winget" } elseif ($app.PSObject.Properties["source"]) { "external" } else { "unknown" } 53 | $appName = if ($app.friendly_name) { $app.friendly_name } elseif ($app.name) { $app.name } elseif ($app.id) { $app.id } else { "UnknownApp" } 54 | $overrideFlags = $null 55 | if ($app.PSObject.Properties["override_flags"]) { 56 | $overrideFlags = $app.override_flags 57 | if ($null -ne $app.override_flags) { 58 | } else { 59 | } 60 | } elseif ($app.PSObject.Properties["OverrideFlags"]) { 61 | $overrideFlags = $app.OverrideFlags 62 | if ($null -ne $app.OverrideFlags) { 63 | } else { 64 | } 65 | } else { 66 | } 67 | $result = @{ name = $appName; type = $appType; status = "skipped"; message = "" } 68 | 69 | if ($appType -eq "winget") { 70 | try { 71 | Write-ToLog -message "Installing winget app: $appName" -log_file $log_file 72 | $wingetArgs = @("install", "--id", $app.id, "--accept-source-agreements", "--accept-package-agreements", "-h") 73 | if ($overrideFlags) { 74 | Write-ToLog -message ("override_flags/OverrideFlags for " + $appName + ": " + $overrideFlags) -log_file $log_file 75 | $wingetArgs += "--override" 76 | $wingetArgs += "`"$overrideFlags`"" 77 | } elseif ($app.install_args) { 78 | $wingetArgs += $app.install_args 79 | } 80 | $wingetArgsString = $wingetArgs -join ' ' 81 | $process = Start-Process -FilePath "winget" -ArgumentList $wingetArgs -PassThru -Wait -NoNewWindow 82 | $exit_code = $process.ExitCode 83 | $success = Test-InstallationSuccess -exit_code $exit_code -app_name $appName -log_file $log_file 84 | if ($success) { 85 | $installedCount++ 86 | # Always add to uninstall tracking immediately, with required fields 87 | $trackingApp = [PSCustomObject]@{ 88 | id = if ($app.id) { $app.id } elseif ($app.name) { $app.name } else { $appName } 89 | name = if ($app.name) { $app.name } elseif ($app.id) { $app.id } else { $appName } 90 | friendly_name = if ($app.friendly_name) { $app.friendly_name } else { $appName } 91 | version = if ($app.version) { $app.version } else { "Latest" } 92 | installed_on = (Get-Date -Format "yyyy-MM-dd HH:mm:ss") 93 | last_updated = (Get-Date -Format "yyyy-MM-dd HH:mm:ss") 94 | } 95 | Append-ToJson -jsonFilePath $uninstall_json_file -section "winget_applications" -newObject $trackingApp 96 | $result.status = "success" 97 | $result.message = "Installed and tracked." 98 | } else { 99 | $failedCount++ 100 | $failedPackages += $appName 101 | $result.status = "failed" 102 | $result.message = "Install failed." 103 | } 104 | } catch { 105 | $failedCount++ 106 | $failedPackages += $appName 107 | Write-ToLog -message ("Exception during winget install for ${appName}: " + ($_ | Out-String)) -log_file $log_file 108 | $result.status = "error" 109 | $result.message = $_.Exception.Message 110 | } 111 | } elseif ($appType -eq "external") { 112 | # Always ensure uninstall tracking is updated for external apps as well, with required fields 113 | $success = Install-ExternalApplication -app $app -log_file $log_file -uninstall_json_file $uninstall_json_file 114 | if ($success) { 115 | $installedCount++ 116 | $result.status = "success" 117 | $result.message = "Installed and tracked." 118 | } else { 119 | $failedCount++ 120 | $failedPackages += $appName 121 | $result.status = "failed" 122 | $result.message = "Install failed." 123 | } 124 | } else { 125 | $skippedCount++ 126 | $result.status = "skipped" 127 | $result.message = "Unknown app type." 128 | } 129 | $results += $result 130 | } 131 | $summary = @{ 132 | TotalPackages = $selectedPackages.Count 133 | SuccessfulInstalls = $installedCount 134 | FailedInstalls = $failedCount 135 | SkippedInstalls = $skippedCount 136 | FailedPackages = if ($failedPackages -and $failedPackages.Count -gt 0) { $failedPackages -join ", " } else { "None" } 137 | } 138 | Write-Host "Install Summary: Total: $($summary.TotalPackages), Installed: $($summary.SuccessfulInstalls), Failed: $($summary.FailedInstalls), Skipped: $($summary.SkippedInstalls), FailedPackages: $($summary.FailedPackages)" -ForegroundColor Green 139 | Write-ToLog -message "Install Summary: Total: $($summary.TotalPackages), Installed: $($summary.SuccessfulInstalls), Failed: $($summary.FailedInstalls), Skipped: $($summary.SkippedInstalls), FailedPackages: $($summary.FailedPackages)" -log_file $log_file 140 | return $summary 141 | } 142 | # Install.ps1 143 | # Module containing all installation-related functions 144 | 145 | # Test if a winget installation was successful 146 | function Test-InstallationSuccess { 147 | param ( 148 | [int]$exit_code, 149 | [string]$app_name, 150 | [string]$log_file 151 | ) 152 | switch ($exit_code) { 153 | 0 { 154 | Write-ToLog -message "Successfully installed $app_name" -log_file $log_file 155 | return $true 156 | } 157 | -1978335189 { 158 | Write-ToLog -message "Application $app_name is already installed" -log_file $log_file 159 | return $true 160 | } 161 | -1978335188 { 162 | Write-ToLog -message "No applicable installer found for $app_name" -log_file $log_file 163 | return $false 164 | } 165 | -1978335186 { 166 | Write-ToLog -message "Installation of $app_name was blocked by policy" -log_file $log_file 167 | return $false 168 | } 169 | # Add any other exit codes that winget might return 170 | -1978335210 { 171 | Write-ToLog -message "Package $app_name not found in the source" -log_file $log_file 172 | return $false 173 | } 174 | -1978335212 { 175 | Write-ToLog -message "Package $app_name is already installed (alternative code)" -log_file $log_file 176 | return $true 177 | } 178 | -1978335181 { 179 | Write-ToLog -message "Application $app_name completed successfully but a reboot is required" -log_file $log_file 180 | return $true 181 | } 182 | -1978335182 { 183 | Write-ToLog -message "Application $app_name installation completed with restart required" -log_file $log_file 184 | return $true 185 | } 186 | 87 { 187 | # Error code for "The parameter is incorrect" - common with some installations 188 | Write-ToLog -message "Application $app_name completed with exit code 87 (parameter incorrect) - likely already installed" -log_file $log_file 189 | return $true 190 | } 191 | 3010 { 192 | # Common installer exit code for reboot required 193 | Write-ToLog -message "Application $app_name successfully installed (reboot required)" -log_file $log_file 194 | return $true 195 | } 196 | 1 { 197 | # Some installers use 1 to indicate success with warnings or already installed 198 | Write-ToLog -message "Application $app_name completed with exit code 1 (success with warnings or already installed)" -log_file $log_file 199 | return $true 200 | } 201 | default { 202 | Write-ToLog -message "Failed to install $app_name. Exit code: $exit_code" -log_file $log_file 203 | return $false 204 | } 205 | } 206 | } 207 | 208 | # Install an external application 209 | function Install-ExternalApplication { 210 | param ( 211 | [PSCustomObject]$app, 212 | [string]$log_file, 213 | [string]$uninstall_json_file 214 | ) 215 | 216 | # Get display name for logging 217 | $appDisplayName = if ($app.friendly_name) { $app.friendly_name } else { $app.name } 218 | 219 | Write-ToLog -message "Installing external application $appDisplayName" -log_file $log_file 220 | 221 | # Check for required properties 222 | if (-not $app.name -or -not $app.source) { 223 | Write-ToLog -message "Error: External application $appDisplayName is missing required properties (name or source)" -log_file $log_file 224 | return $false 225 | } 226 | 227 | # Create a temporary directory for downloads if it doesn't exist 228 | $temp_dir = Join-Path $env:TEMP "EnvSetup_Downloads" 229 | if (-not (Test-Path $temp_dir)) { 230 | New-Item -ItemType Directory -Path $temp_dir -Force | Out-Null 231 | } 232 | 233 | try { 234 | # Download the installer 235 | $installer_path = Join-Path $temp_dir "$($app.name)_installer$(Split-Path $app.source -Extension)" 236 | try { 237 | Write-ToLog -message "Downloading $($appDisplayName) from $($app.source)" -log_file $log_file 238 | Invoke-WebRequest -Uri $app.source -OutFile $installer_path -UseBasicParsing 239 | Write-ToLog -message "Downloaded installer for $($appDisplayName) to $installer_path" -log_file $log_file 240 | } 241 | catch { 242 | Write-ToLog -message "Failed to download installer for $($appDisplayName): $_" -log_file $log_file 243 | return $false 244 | } 245 | 246 | # Run the installer 247 | $arguments = @() 248 | if ($app.install_flags) { 249 | $arguments = $app.install_flags -split '\s+' 250 | } elseif ($app.install_args) { 251 | # For backward compatibility 252 | $arguments = $app.install_args -split '\s+' 253 | } 254 | 255 | Write-ToLog -message "Running installer for $appDisplayName with arguments: $($arguments -join ' ')" -log_file $log_file 256 | $process = Start-Process -FilePath $installer_path -ArgumentList $arguments -PassThru -Wait -NoNewWindow 257 | $exit_code = $process.ExitCode 258 | 259 | $success = ($exit_code -eq 0) 260 | Write-ToLog -message "Installation of $($appDisplayName) completed with exit code $exit_code" -log_file $log_file 261 | 262 | # Always add to tracking if install succeeded or app is already installed (1603) 263 | if ($success -or $exit_code -eq 1603) { 264 | # Add installation timestamp and additional info to tracking 265 | $trackingApp = [PSCustomObject]@{ 266 | name = if ($app.name) { $app.name } else { $appDisplayName } 267 | friendly_name = if ($app.friendly_name) { $app.friendly_name } else { $appDisplayName } 268 | version = if ($app.version) { $app.version } else { "Latest" } 269 | uninstall_command = if ($app.PSObject.Properties.Name -contains "uninstall_command" -and $app.uninstall_command) { $app.uninstall_command } else { "" } 270 | installed_on = (Get-Date -Format "yyyy-MM-dd HH:mm:ss") 271 | last_updated = (Get-Date -Format "yyyy-MM-dd HH:mm:ss") 272 | } 273 | # Add status for already installed applications 274 | if ($exit_code -eq 1603) { 275 | $trackingApp | Add-Member -MemberType NoteProperty -Name "installation_status" -Value "already_installed" 276 | Write-ToLog -message "$appDisplayName appears to be already installed. Adding to tracking file anyway." -log_file $log_file 277 | $success = $true 278 | } 279 | # Handle tracking based on mode 280 | if (-not [string]::IsNullOrWhiteSpace($uninstall_json_file)) { 281 | # GUI mode: append to JSON file immediately 282 | $retryCount = 0 283 | $maxRetries = 3 284 | $success_append = $false 285 | while ($retryCount -lt $maxRetries -and -not $success_append) { 286 | try { 287 | # Add a small delay to prevent file access conflicts 288 | if ($retryCount -gt 0) { 289 | Start-Sleep -Milliseconds (100 * $retryCount) 290 | } 291 | Append-ToJson -jsonFilePath $uninstall_json_file -section "external_applications" -newObject $trackingApp 292 | $success_append = $true 293 | Write-ToLog -message "Added/updated $appDisplayName in tracking file for uninstallation" -log_file $log_file 294 | } 295 | catch { 296 | $retryCount++ 297 | Write-ToLog -message "Retry $retryCount/$maxRetries`: Failed to update tracking file for $appDisplayName`: $_" -log_file $log_file 298 | if ($retryCount -eq $maxRetries) { 299 | Write-ToLog -message "Failed to add $appDisplayName to tracking file after $maxRetries attempts" -log_file $log_file 300 | } 301 | } 302 | } 303 | } 304 | # No batch mode: all tracking is immediate per-app 305 | } 306 | 307 | return $success 308 | } 309 | catch { 310 | Write-ToLog -message "Error during installation of $($appDisplayName): $_" -log_file $log_file 311 | return $false 312 | } 313 | } 314 | 315 | -------------------------------------------------------------------------------- /Windows_Software_Installation/WingetGUI_Installer/Public/Append-ToJson.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | Helper function to append to a JSON file 3 | Appends an object to a specified section of a JSON file 4 | #> 5 | function Append-ToJson { 6 | param ( 7 | [Parameter(Mandatory=$true)] 8 | [string]$jsonFilePath, 9 | 10 | [Parameter(Mandatory=$true)] 11 | [ValidateSet("winget_applications", "external_applications")] 12 | [string]$section, 13 | 14 | [Parameter(Mandatory=$true)] 15 | [PSCustomObject]$newObject 16 | ) 17 | 18 | # Simple retry mechanism with exponential backoff 19 | $maxRetries = 5 20 | $retryCount = 0 21 | $success = $false 22 | 23 | while ($retryCount -lt $maxRetries -and -not $success) { 24 | try { 25 | # Check if the JSON file exists 26 | if (-not (Test-Path -Path $jsonFilePath)) { 27 | # Create the directory if it doesn't exist 28 | $jsonDir = Split-Path -Parent $jsonFilePath 29 | if (-not (Test-Path $jsonDir)) { 30 | New-Item -Path $jsonDir -ItemType Directory -Force | Out-Null 31 | } 32 | 33 | # Create a new JSON file with empty arrays 34 | $baseJson = @{ 35 | "winget_applications" = @() 36 | "external_applications" = @() 37 | } 38 | $baseJson | ConvertTo-Json -Depth 5 | Set-Content -Path $jsonFilePath -Encoding UTF8 39 | } 40 | 41 | # Read the existing JSON with error handling 42 | $jsonContent = $null 43 | try { 44 | $jsonText = Get-Content -Path $jsonFilePath -Raw -Encoding UTF8 45 | if ([string]::IsNullOrWhiteSpace($jsonText)) { 46 | # Empty file, create default structure 47 | $jsonContent = @{ 48 | "winget_applications" = @() 49 | "external_applications" = @() 50 | } 51 | } else { 52 | $jsonContent = $jsonText | ConvertFrom-Json 53 | } 54 | } 55 | catch { 56 | Write-Warning "JSON file appears to be corrupted. Creating new file." 57 | # Create a new JSON file with empty arrays 58 | $jsonContent = @{ 59 | "winget_applications" = @() 60 | "external_applications" = @() 61 | } 62 | } 63 | 64 | # Ensure the section exists 65 | if (-not ($jsonContent.PSObject.Properties.Name -contains $section)) { 66 | $jsonContent | Add-Member -MemberType NoteProperty -Name $section -Value @() 67 | } elseif ($null -eq $jsonContent.$section) { 68 | $jsonContent.$section = @() 69 | } 70 | 71 | # Use the array directly (do not wrap in @()) 72 | $sectionArray = $jsonContent.$section 73 | 74 | # Check if object already exists by name or id 75 | $exists = $false 76 | $foundIndex = -1 77 | 78 | for ($i = 0; $i -lt $sectionArray.Count; $i++) { 79 | $item = $sectionArray[$i] 80 | # Check for match by id first (more reliable), then by name 81 | if (($newObject.PSObject.Properties.Name -contains "id" -and 82 | $item.PSObject.Properties.Name -contains "id" -and 83 | $item.id -eq $newObject.id) -or 84 | ($item.name -eq $newObject.name)) { 85 | $exists = $true 86 | $foundIndex = $i 87 | break 88 | } 89 | } 90 | 91 | # Add the object if it doesn't exist, otherwise update it 92 | if (-not $exists) { 93 | # Add new object to the array 94 | $sectionArray += $newObject 95 | $jsonContent.$section = $sectionArray 96 | 97 | # Log the addition for debugging 98 | Write-Host "Added new application to ${section}: $($newObject.name)" -ForegroundColor Green 99 | } else { 100 | # Update existing object 101 | if ($foundIndex -ge 0) { 102 | # Create a combined object 103 | $combinedObject = $sectionArray[$foundIndex].PSObject.Copy() 104 | 105 | # Update properties from the new object 106 | foreach ($property in $newObject.PSObject.Properties) { 107 | if ($combinedObject.PSObject.Properties.Name -contains $property.Name) { 108 | $combinedObject.$($property.Name) = $property.Value 109 | } else { 110 | $combinedObject | Add-Member -MemberType NoteProperty -Name $property.Name -Value $property.Value 111 | } 112 | } 113 | 114 | # Update the array 115 | $sectionArray[$foundIndex] = $combinedObject 116 | $jsonContent.$section = $sectionArray 117 | 118 | # Log the update for debugging 119 | Write-Host "Updated existing application in ${section}: $($newObject.name)" -ForegroundColor Cyan 120 | } 121 | } 122 | 123 | # Save the updated JSON with proper encoding 124 | $jsonString = $jsonContent | ConvertTo-Json -Depth 5 125 | Set-Content -Path $jsonFilePath -Value $jsonString -Encoding UTF8 126 | 127 | $success = $true 128 | } 129 | catch { 130 | $retryCount++ 131 | if ($retryCount -lt $maxRetries) { 132 | # Exponential backoff: wait longer each time 133 | $waitTime = [Math]::Min(1000, 50 * [Math]::Pow(2, $retryCount)) 134 | Start-Sleep -Milliseconds $waitTime 135 | } else { 136 | throw "Failed to update JSON file after $maxRetries attempts: $_" 137 | } 138 | } 139 | } 140 | } 141 | 142 | # Maintain compatibility with older code that uses this function name 143 | function AppendToJson { 144 | param ( 145 | [string]$json_location, 146 | [hashtable]$data 147 | ) 148 | 149 | # Validate that data has the required structure 150 | if (-not $data.ContainsKey('winget_applications') -or -not $data.ContainsKey('external_applications')) { 151 | throw "Data must contain winget_applications and external_applications keys" 152 | } 153 | 154 | # Check if the file exists 155 | if (Test-Path -Path $json_location) { 156 | # Load existing data 157 | $existing_data = Get-Content -Path $json_location -Raw | ConvertFrom-Json 158 | 159 | # Set merged data to existing so we can add without altering immediately 160 | $merged_data = $existing_data 161 | 162 | # Initialize arrays if they don't exist 163 | if (-not $merged_data.winget_applications) { 164 | $merged_data.winget_applications = @() 165 | } 166 | if (-not $merged_data.external_applications) { 167 | $merged_data.external_applications = @() 168 | } 169 | 170 | # Append winget_applications if not already present 171 | if ($data.ContainsKey('winget_applications')) { 172 | foreach ($new_app in $data.winget_applications) { 173 | # Check if application already exists (by id first, then by name) 174 | $exists = $false 175 | $foundIndex = -1 176 | $index = 0 177 | 178 | foreach ($existing_app in $merged_data.winget_applications) { 179 | # Check for match by id first (more reliable), then by name 180 | if (($new_app.PSObject.Properties.Name -contains "id" -and 181 | $existing_app.PSObject.Properties.Name -contains "id" -and 182 | $existing_app.id -eq $new_app.id) -or 183 | ($existing_app.name -eq $new_app.name)) { 184 | $exists = $true 185 | $foundIndex = $index 186 | break 187 | } 188 | $index++ 189 | } 190 | 191 | if (-not $exists) { 192 | # Add new application 193 | $merged_data.winget_applications += $new_app 194 | Write-Host "Added new winget application: $($new_app.name)" -ForegroundColor Green 195 | } else { 196 | # Update existing application with combined properties 197 | $combinedApp = $merged_data.winget_applications[$foundIndex].PSObject.Copy() 198 | 199 | # Update properties from the new object 200 | foreach ($property in $new_app.PSObject.Properties) { 201 | if ($combinedApp.PSObject.Properties.Name -contains $property.Name) { 202 | # Update existing property 203 | $combinedApp.$($property.Name) = $property.Value 204 | } else { 205 | # Add new property 206 | $combinedApp | Add-Member -MemberType NoteProperty -Name $property.Name -Value $property.Value 207 | } 208 | } 209 | 210 | # Update in array 211 | $merged_data.winget_applications[$foundIndex] = $combinedApp 212 | Write-Host "Updated existing winget application: $($new_app.name)" -ForegroundColor Cyan 213 | } 214 | } 215 | } 216 | else { 217 | $merged_data.winget_applications = @() 218 | } 219 | 220 | # Append external_applications if not already present 221 | if ($data.ContainsKey('external_applications')) { 222 | foreach ($new_app in $data.external_applications) { 223 | # Check if application already exists (by name) 224 | $exists = $false 225 | $foundIndex = -1 226 | $index = 0 227 | 228 | foreach ($existing_app in $merged_data.external_applications) { 229 | if ($existing_app.name -eq $new_app.name) { 230 | $exists = $true 231 | $foundIndex = $index 232 | break 233 | } 234 | $index++ 235 | } 236 | 237 | if (-not $exists) { 238 | # Add new application 239 | $merged_data.external_applications += $new_app 240 | Write-Host "Added new external application: $($new_app.name)" -ForegroundColor Green 241 | } else { 242 | # Update existing application with combined properties 243 | $combinedApp = $merged_data.external_applications[$foundIndex].PSObject.Copy() 244 | 245 | # Update properties from the new object 246 | foreach ($property in $new_app.PSObject.Properties) { 247 | if ($combinedApp.PSObject.Properties.Name -contains $property.Name) { 248 | # Update existing property 249 | $combinedApp.$($property.Name) = $property.Value 250 | } else { 251 | # Add new property 252 | $combinedApp | Add-Member -MemberType NoteProperty -Name $property.Name -Value $property.Value 253 | } 254 | } 255 | 256 | # Update in array 257 | $merged_data.external_applications[$foundIndex] = $combinedApp 258 | Write-Host "Updated existing external application: $($new_app.name)" -ForegroundColor Cyan 259 | } 260 | } 261 | } 262 | else { 263 | $merged_data.external_applications = @() 264 | } 265 | 266 | # Convert merged data back to JSON and save 267 | $json_string = $merged_data | ConvertTo-Json -Depth 5 268 | Set-Content -Path $json_location -Value $json_string 269 | } 270 | else { 271 | # File doesn't exist, create new with data 272 | $json_dir = Split-Path -Parent $json_location 273 | if (-not (Test-Path $json_dir)) { 274 | New-Item -Path $json_dir -ItemType Directory 275 | } 276 | New-Item -Path $json_location -ItemType File 277 | $json_string = $data | ConvertTo-Json -Depth 5 278 | Set-Content -Path $json_location -Value $json_string 279 | } 280 | } 281 | 282 | <# 283 | Helper function to remove an object from a specified section of a JSON file by id 284 | #> 285 | function Remove-FromJsonById { 286 | param ( 287 | [Parameter(Mandatory=$true)] 288 | [string]$jsonFilePath, 289 | [Parameter(Mandatory=$true)] 290 | [ValidateSet("winget_applications", "external_applications")] 291 | [string]$section, 292 | [Parameter(Mandatory=$true)] 293 | [string]$id 294 | ) 295 | 296 | Write-Host "Remove-FromJsonById called with: $jsonFilePath, $section, $id" -ForegroundColor Magenta 297 | 298 | if (-not (Test-Path -Path $jsonFilePath)) { 299 | Write-Warning "JSON file does not exist: $jsonFilePath" 300 | return 301 | } 302 | 303 | $jsonText = Get-Content -Path $jsonFilePath -Raw -Encoding UTF8 304 | if ([string]::IsNullOrWhiteSpace($jsonText)) { 305 | Write-Warning "JSON file is empty: $jsonFilePath" 306 | return 307 | } 308 | 309 | $jsonContent = $jsonText | ConvertFrom-Json 310 | 311 | if (-not ($jsonContent.PSObject.Properties.Name -contains $section)) { 312 | Write-Warning "Section '$section' does not exist in JSON." 313 | return 314 | } 315 | 316 | # Always treat as array, even if only one object 317 | $sectionArray = @() 318 | if ($jsonContent.$section -is [System.Collections.IEnumerable] -and 319 | -not ($jsonContent.$section -is [string])) { 320 | $sectionArray = @($jsonContent.$section) 321 | } elseif ($null -ne $jsonContent.$section) { 322 | $sectionArray = @($jsonContent.$section) 323 | } 324 | 325 | # Flatten in case it's an array of arrays (PowerShell quirk) 326 | $flatArray = @() 327 | foreach ($item in $sectionArray) { 328 | if ($item -is [System.Collections.IEnumerable] -and -not ($item -is [string])) { 329 | $flatArray += $item 330 | } else { 331 | $flatArray += ,$item 332 | } 333 | } 334 | 335 | # Remove the entry by id (case-insensitive, trimmed) 336 | $filteredArray = @() 337 | foreach ($item in $flatArray) { 338 | $itemId = "" 339 | if ($item.PSObject.Properties.Name -contains "id") { 340 | $itemId = ($item.id | Out-String).Trim() 341 | } 342 | if ($itemId -ieq $id.Trim()) { 343 | Write-Host "Match found: Removing item.id '$itemId' (target id: '$($id.Trim())')" -ForegroundColor DarkYellow 344 | # Do not add to filteredArray, i.e., remove it 345 | } else { 346 | $filteredArray += $item 347 | } 348 | } 349 | 350 | $jsonContent.$section = $filteredArray 351 | 352 | # If both arrays are empty, delete the file 353 | $wingetEmpty = -not $jsonContent.winget_applications -or $jsonContent.winget_applications.Count -eq 0 354 | $externalEmpty = -not $jsonContent.external_applications -or $jsonContent.external_applications.Count -eq 0 355 | 356 | if ($wingetEmpty -and $externalEmpty) { 357 | Remove-Item -Path $jsonFilePath -Force 358 | Write-Host "All applications removed. Deleted $jsonFilePath." -ForegroundColor Red 359 | } else { 360 | # Save the updated JSON 361 | $jsonString = $jsonContent | ConvertTo-Json -Depth 5 362 | Set-Content -Path $jsonFilePath -Value $jsonString -Encoding UTF8 363 | Write-Host "Removed application from $section by id: $id" -ForegroundColor Yellow 364 | } 365 | } 366 | -------------------------------------------------------------------------------- /Windows_Software_Installation/WingetGUI_Installer/Public/Uninstall.ps1: -------------------------------------------------------------------------------- 1 | # Uninstall.ps1 2 | # Module containing all uninstallation-related functions 3 | 4 | # Test if a winget uninstallation was successful 5 | function Test-UninstallationSuccess { 6 | param ( 7 | [int]$exit_code, 8 | [string]$app_name, 9 | [string]$log_file 10 | ) 11 | 12 | switch ($exit_code) { 13 | 0 { 14 | Write-ToLog -message "Successfully uninstalled $app_name" -log_file $log_file 15 | return $true 16 | } 17 | -1978335189 { 18 | Write-ToLog -message "Application $app_name is not installed" -log_file $log_file 19 | return $true # Still return success, since the goal is for the app to not be installed 20 | } 21 | -1978335188 { 22 | Write-ToLog -message "No applicable uninstaller found for $app_name" -log_file $log_file 23 | return $true # Consider it success, since we can't uninstall what doesn't exist 24 | } 25 | -1978335186 { 26 | Write-ToLog -message "Uninstallation of $app_name was blocked by policy" -log_file $log_file 27 | return $false 28 | } 29 | -1978335185 { 30 | Write-ToLog -message "No packages found to uninstall for $app_name" -log_file $log_file 31 | return $true # Still return success, since the goal is for the app to not be installed 32 | } 33 | 3010 { 34 | Write-ToLog -message "Successfully uninstalled $app_name (reboot required)" -log_file $log_file 35 | return $true 36 | } 37 | 1641 { 38 | Write-ToLog -message "Successfully uninstalled $app_name (initiated reboot)" -log_file $log_file 39 | return $true 40 | } 41 | default { 42 | Write-ToLog -message "Uninstallation of $app_name completed with exit code: $exit_code" -log_file $log_file 43 | return $exit_code -eq 0 # For any other code, return true only if it's 0 44 | } 45 | } 46 | } 47 | 48 | # Used by the GUI to uninstall selected packages 49 | function Uninstall-SelectedPackages { 50 | param ( 51 | [array]$selectedPackages, 52 | [string]$log_file, 53 | [string]$json_uninstall_file_path 54 | ) 55 | 56 | # Prepare result tracking 57 | $results = @{ 58 | TotalPackages = $selectedPackages.Count 59 | SuccessfulUninstalls = 0 60 | FailedUninstalls = 0 61 | FailedPackages = @() 62 | } 63 | 64 | foreach ($package in $selectedPackages) { 65 | # Create app object from the package information in the datatable 66 | if ($package.Type -eq "Winget") { 67 | $app = [PSCustomObject]@{ 68 | id = $package.Id 69 | friendly_name = $package.FriendlyName 70 | version = if ($package.Version -eq "Latest") { $null } else { $package.Version } 71 | } 72 | $section = "winget_applications" 73 | $id = $package.Id 74 | } else { 75 | $app = [PSCustomObject]@{ 76 | name = $package.Id 77 | friendly_name = $package.FriendlyName 78 | version = if ($package.Version -eq "Latest") { $null } else { $package.Version } 79 | } 80 | $section = "external_applications" 81 | $id = $package.Id 82 | } 83 | 84 | # For external applications, look up the full details including uninstall_command 85 | if ($package.Type -eq "External") { 86 | $uninstallJson = Get-Content -Path $json_uninstall_file_path -Raw | ConvertFrom-Json 87 | $originalApp = $uninstallJson.external_applications | Where-Object { $_.name -eq $app.name } | Select-Object -First 1 88 | if ($originalApp) { 89 | $app = $originalApp 90 | } 91 | } 92 | 93 | try { 94 | if ($app.PSObject.Properties.Name -contains "uninstall_command") { 95 | $success = Uninstall-ExternalApplication -app $app -log_file $log_file 96 | } else { 97 | $success = Uninstall-WingetApplication -app $app -log_file $log_file 98 | } 99 | 100 | if ($success) { 101 | $results.SuccessfulUninstalls++ 102 | # Remove from uninstall.json after successful uninstall 103 | Remove-FromJsonById -jsonFilePath $json_uninstall_file_path -section $section -id $id 104 | } else { 105 | $results.FailedUninstalls++ 106 | $appName = if ($app.friendly_name) { $app.friendly_name } else { if ($app.id) { $app.id } else { $app.name } } 107 | $results.FailedPackages += $appName 108 | } 109 | } catch { 110 | $appIdentifier = if ($app.id) { $app.id } else { $app.name } 111 | Write-ToLog -message "Error uninstalling $appIdentifier`: $_" -log_file $log_file 112 | $results.FailedUninstalls++ 113 | $appName = if ($app.friendly_name) { $app.friendly_name } else { $appIdentifier } 114 | $results.FailedPackages += $appName 115 | } 116 | } 117 | 118 | return $results 119 | } 120 | 121 | # Uninstall a winget application 122 | function Uninstall-WingetApplication { 123 | param ( 124 | [PSCustomObject]$app, 125 | [string]$log_file 126 | ) 127 | 128 | # Validate app object has required properties 129 | if (-not $app -or (-not $app.id -and -not $app.name)) { 130 | Write-ToLog -message "Error: Invalid application object provided to Uninstall-WingetApplication. Must have id or name property." -log_file $log_file 131 | return $false 132 | } 133 | 134 | # Determine the application identifier to use (prefer id, fall back to name) 135 | $appIdentifier = if ($app.id) { $app.id } else { $app.name } 136 | $appDisplayName = if ($app.friendly_name) { $app.friendly_name } else { $appIdentifier } 137 | 138 | # Log what we're about to uninstall 139 | Write-ToLog -message "Uninstalling application: $appDisplayName $(if ($app.version) { "version $($app.version)" } else { "(any version)" })" -log_file $log_file 140 | 141 | # Construct arguments for winget uninstallation with comprehensive silent flags 142 | $arguments = @( 143 | "uninstall", 144 | "--purge", 145 | "--accept-source-agreements", 146 | "--silent", 147 | "--disable-interactivity", 148 | "--force" # Force uninstall without confirmation dialogs 149 | ) 150 | 151 | # Add the application ID 152 | $arguments += @("--id", $appIdentifier) 153 | 154 | if ($app.version -and $app.version -ne "Latest" -and $app.version -ne "" -and $app.version -ne $null) { 155 | $arguments += @("-v", $app.version) 156 | } 157 | 158 | # Add uninstall override flags if they exist for this application 159 | if ($app.uninstall_override_flags) { 160 | $arguments += @("--override", $app.uninstall_override_flags) 161 | Write-ToLog -message "Using custom uninstall override flags for ${appDisplayName}: $($app.uninstall_override_flags)" -log_file $log_file 162 | } 163 | 164 | Write-ToLog -message "Uninstalling $appDisplayName" -log_file $log_file 165 | 166 | # Set comprehensive environment variables to suppress ALL UI elements 167 | $env:WINGET_DISABLE_INTERACTIVITY = "1" 168 | $env:WINGET_DISABLE_UPGRADE_PROMPTS = "1" 169 | $env:WINGET_DISABLE_CONFIRMATION = "1" 170 | $env:SILENT = "1" 171 | $env:QUIET = "1" 172 | 173 | # Log the full command we're about to execute 174 | $commandStr = "winget $($arguments -join ' ')" 175 | Write-ToLog -message "Executing command: $commandStr" -log_file $log_file 176 | 177 | try { 178 | $process = Start-Process -FilePath winget -ArgumentList $arguments -PassThru -Wait -NoNewWindow 179 | $exit_code = $process.ExitCode 180 | 181 | return Test-UninstallationSuccess -exit_code $exit_code -app_name $appDisplayName -log_file $log_file 182 | } 183 | catch { 184 | Write-ToLog -message "Error during uninstallation of ${appDisplayName}: $_" -log_file $log_file 185 | return $false 186 | } 187 | } 188 | 189 | # Uninstall an external application 190 | function Uninstall-ExternalApplication { 191 | param ( 192 | [PSCustomObject]$app, 193 | [string]$log_file 194 | ) 195 | 196 | # Get display name for logging 197 | $appDisplayName = if ($app.friendly_name) { $app.friendly_name } else { $app.name } 198 | 199 | # Validate app object has required properties 200 | if (-not $app -or -not $app.name) { 201 | Write-ToLog -message "Error: Invalid application object for external application" -log_file $log_file 202 | return $false 203 | } 204 | 205 | if (-not $app.uninstall_command) { 206 | Write-ToLog -message "Warning: No uninstall command provided for $appDisplayName. Considering it already uninstalled." -log_file $log_file 207 | return $true # Return success since there's nothing to uninstall 208 | } 209 | 210 | Write-ToLog -message "Uninstalling external application: $appDisplayName" -log_file $log_file 211 | Write-ToLog -message "Using command: $($app.uninstall_command)" -log_file $log_file 212 | 213 | $regex = '([a-zA-Z]:.*.exe)(.*)' # Regex to match the uninstall command 214 | if ($app.uninstall_command -match $regex) { 215 | $command = $matches[1] 216 | $arguments_unsplit = $matches[2] 217 | 218 | # Check if the executable exists 219 | if (-not (Test-Path -Path $command)) { 220 | Write-ToLog -message "Warning: Uninstall executable not found at: $command for $appDisplayName. Considering it already uninstalled." -log_file $log_file 221 | return $true # Return success since there's nothing to uninstall 222 | } 223 | 224 | # Split the arguments properly 225 | $arguments_split = @() 226 | if (-not [string]::IsNullOrWhiteSpace($arguments_unsplit)) { 227 | $arguments_split = $arguments_unsplit -split ' (?=(?:[^\\"]*\\"[^\\"]*\\")*[^\\"]*$)' | 228 | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | 229 | ForEach-Object { $_.Trim('\\"') } 230 | } 231 | 232 | Write-ToLog -message "Parsed command: $command" -log_file $log_file 233 | Write-ToLog -message "Parsed arguments: $($arguments_split -join ', ')" -log_file $log_file 234 | 235 | try { 236 | $process = Start-Process -FilePath $command -ArgumentList $arguments_split -PassThru -Wait -NoNewWindow 237 | $exit_code = $process.ExitCode 238 | Write-ToLog -message "Uninstalled $appDisplayName with exit code $exit_code" -log_file $log_file 239 | 240 | # Consider any exit code as success for external applications, as different installers use different codes 241 | # For applications like Visual Studio, the uninstaller might return a non-zero exit code even on success 242 | if ($exit_code -eq 0) { 243 | return $true 244 | } else { 245 | # Check known "success" exit codes from common uninstallers 246 | $successExitCodes = @(0, 3010, 1641) # 3010 = Reboot required, 1641 = Initiated reboot 247 | if ($successExitCodes -contains $exit_code) { 248 | Write-ToLog -message "Uninstallation of $appDisplayName successful with expected exit code $exit_code" -log_file $log_file 249 | return $true 250 | } else { 251 | Write-ToLog -message "Uninstallation of $appDisplayName may have failed with exit code $exit_code" -log_file $log_file 252 | # Return true anyway to remove from tracking file, as we can't reliably determine failure for external apps 253 | return $true 254 | } 255 | } 256 | } 257 | catch { 258 | Write-ToLog -message "Error during uninstallation of external application ${appDisplayName}: $_" -log_file $log_file 259 | return $false 260 | } 261 | } 262 | else { 263 | Write-ToLog -message "Invalid uninstall command format for ${appDisplayName}: $($app.uninstall_command)" -log_file $log_file 264 | return $false 265 | } 266 | } 267 | 268 | # Batch uninstallation function used by the command-line mode 269 | function Invoke-BatchUninstall { 270 | param ( 271 | [string]$json_uninstall_file_path, 272 | [string]$uninstall_log_file 273 | ) 274 | 275 | Write-Host "Starting batch uninstallation process..." -ForegroundColor Cyan 276 | Write-ToLog -message "Starting batch uninstallation from $json_uninstall_file_path" -log_file $uninstall_log_file 277 | 278 | # Check if the uninstall JSON file exists 279 | if (-not (Test-Path -Path $json_uninstall_file_path)) { 280 | $errorMsg = "Uninstall JSON file not found at: $json_uninstall_file_path" 281 | Write-Host $errorMsg -ForegroundColor Red 282 | Write-ToLog -message $errorMsg -log_file $uninstall_log_file 283 | return 284 | } 285 | 286 | # Try to read the uninstall JSON file 287 | try { 288 | $applications = Get-Content -Path $json_uninstall_file_path -Raw | ConvertFrom-Json 289 | Write-Host "Successfully loaded uninstall data" -ForegroundColor Green 290 | } 291 | catch { 292 | $errorMsg = "Error reading uninstall JSON file: $_" 293 | Write-Host $errorMsg -ForegroundColor Red 294 | Write-ToLog -message $errorMsg -log_file $uninstall_log_file 295 | return 296 | } 297 | 298 | # Initialize success trackers 299 | $successfulWingetUninstalls = 0 300 | $failedWingetUninstalls = 0 301 | $successfulExternalUninstalls = 0 302 | $failedExternalUninstalls = 0 303 | 304 | # Import Remove-FromJsonById from Append-ToJson.ps1 if not already available 305 | if (-not (Get-Command Remove-FromJsonById -ErrorAction SilentlyContinue)) { 306 | $appendToJsonPath = Join-Path -Path (Split-Path $PSScriptRoot -Parent) -ChildPath "Public\Append-ToJson.ps1" 307 | if (Test-Path $appendToJsonPath) { 308 | . $appendToJsonPath 309 | } 310 | } 311 | 312 | # Uninstall winget applications 313 | if ($applications.winget_applications -and $applications.winget_applications.Count -gt 0) { 314 | Write-Host "Uninstalling $($applications.winget_applications.Count) winget applications..." -ForegroundColor Cyan 315 | Write-ToLog -message "Uninstalling $($applications.winget_applications.Count) winget applications" -log_file $uninstall_log_file 316 | 317 | foreach ($app in $applications.winget_applications) { 318 | $appName = if ($app.friendly_name) { $app.friendly_name } else { if ($app.id) { $app.id } else { $app.name } } 319 | Write-Host "Uninstalling winget application: $appName" -ForegroundColor Cyan 320 | 321 | $success = Uninstall-WingetApplication -app $app -log_file $uninstall_log_file 322 | if ($success) { 323 | $successfulWingetUninstalls++ 324 | # Remove from uninstall.json immediately after uninstall 325 | Remove-FromJsonById -jsonFilePath $json_uninstall_file_path -section "winget_applications" -id $app.id 326 | Write-Host "Successfully uninstalled and removed from tracking: $appName" -ForegroundColor Green 327 | } else { 328 | $failedWingetUninstalls++ 329 | Write-Host "Failed to uninstall: $appName" -ForegroundColor Red 330 | } 331 | } 332 | } else { 333 | Write-Host "No winget applications found to uninstall" -ForegroundColor Yellow 334 | Write-ToLog -message "No winget applications found to uninstall" -log_file $uninstall_log_file 335 | } 336 | 337 | # Uninstall external applications 338 | if ($applications.external_applications -and $applications.external_applications.Count -gt 0) { 339 | Write-Host "Uninstalling $($applications.external_applications.Count) external applications..." -ForegroundColor Cyan 340 | Write-ToLog -message "Uninstalling $($applications.external_applications.Count) external applications" -log_file $uninstall_log_file 341 | 342 | foreach ($app in $applications.external_applications) { 343 | $appName = if ($app.friendly_name) { $app.friendly_name } else { $app.name } 344 | Write-Host "Uninstalling external application: $appName" -ForegroundColor Cyan 345 | 346 | $success = Uninstall-ExternalApplication -app $app -log_file $uninstall_log_file 347 | if ($success) { 348 | $successfulExternalUninstalls++ 349 | # Remove from uninstall.json immediately after uninstall 350 | Remove-FromJsonById -jsonFilePath $json_uninstall_file_path -section "external_applications" -id $app.name 351 | Write-Host "Successfully uninstalled and removed from tracking: $appName" -ForegroundColor Green 352 | } else { 353 | $failedExternalUninstalls++ 354 | Write-Host "Failed to uninstall: $appName" -ForegroundColor Red 355 | } 356 | } 357 | } else { 358 | Write-Host "No external applications found to uninstall" -ForegroundColor Yellow 359 | Write-ToLog -message "No external applications found to uninstall" -log_file $uninstall_log_file 360 | } 361 | 362 | # At this point, Remove-FromJsonById will have deleted uninstall.json if all apps are removed. 363 | # If the file still exists, update it (for any failed uninstalls) 364 | if (Test-Path $json_uninstall_file_path) { 365 | try { 366 | $applications = Get-Content -Path $json_uninstall_file_path -Raw | ConvertFrom-Json 367 | $applications | ConvertTo-Json -Depth 4 | Set-Content -Path $json_uninstall_file_path -Force 368 | Write-Host "Updated uninstall tracking file" -ForegroundColor Green 369 | Write-ToLog -message "Updated uninstall tracking file" -log_file $uninstall_log_file 370 | } 371 | catch { 372 | Write-Host "Error updating uninstall tracking file: $_" -ForegroundColor Red 373 | Write-ToLog -message "Error updating uninstall tracking file: $_" -log_file $uninstall_log_file 374 | } 375 | } else { 376 | Write-Host "Uninstall tracking file removed (all apps uninstalled)." -ForegroundColor Green 377 | Write-ToLog -message "Uninstall tracking file removed (all apps uninstalled)." -log_file $uninstall_log_file 378 | } 379 | 380 | # Summarize results 381 | Write-Host "`nUninstallation Summary:" -ForegroundColor Yellow 382 | Write-Host "--------------------" -ForegroundColor Yellow 383 | Write-Host "Winget Applications: $successfulWingetUninstalls successful, $failedWingetUninstalls failed" -ForegroundColor White 384 | Write-Host "External Applications: $successfulExternalUninstalls successful, $failedExternalUninstalls failed" -ForegroundColor White 385 | Write-Host "Total: $($successfulWingetUninstalls + $successfulExternalUninstalls) successful, $($failedWingetUninstalls + $failedExternalUninstalls) failed" -ForegroundColor White 386 | 387 | # Log summary 388 | Write-ToLog -message "Uninstallation Summary: $successfulWingetUninstalls winget apps successful, $failedWingetUninstalls failed" -log_file $uninstall_log_file 389 | Write-ToLog -message "Uninstallation Summary: $successfulExternalUninstalls external apps successful, $failedExternalUninstalls failed" -log_file $uninstall_log_file 390 | } 391 | --------------------------------------------------------------------------------