Public/Disable-CopilotAIFeature.ps1

function Disable-CopilotAIFeature {
    <#
    .SYNOPSIS
        Disables specific Windows AI features on Copilot+ PCs.

    .DESCRIPTION
        Configures registry policies, stops services, and disables scheduled
        tasks for specified Windows AI features. Supports targeting individual
        features or all features at once.

        Features:
        - Recall: Disables Windows Recall (snapshots, AI data analysis)
        - ClickToDo: Disables Click to Do visual assistant
        - WindowsAI: Disables the Windows AI Fabric Service (WSAIFabricSvc)
        - All: Disables all of the above

        All changes are reversible via Enable-CopilotAIFeature.

    .PARAMETER Feature
        One or more features to disable. Accepts multiple values.

    .EXAMPLE
        Disable-CopilotAIFeature -Feature Recall

        Disable only Windows Recall.

    .EXAMPLE
        Disable-CopilotAIFeature -Feature All -WhatIf

        Preview all changes that would be made to disable every AI feature.

    .EXAMPLE
        Disable-CopilotAIFeature -Feature Recall, ClickToDo

        Disable Recall and Click to Do but leave the AI Fabric Service running.

    .LINK
        https://github.com/DailenG/WinslopFix
    #>

    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium')]
    param(
        [Parameter(Mandatory)]
        [ValidateSet('Recall', 'ClickToDo', 'WindowsAI', 'All')]
        [string[]]$Feature
    )

    process {
        Assert-Administrator

        # Expand 'All' into individual features
        if ('All' -in $Feature) {
            $Feature = @('Recall', 'ClickToDo', 'WindowsAI')
        }

        $results = [System.Collections.Generic.List[PSCustomObject]]::new()

        # --- Recall ---
        if ('Recall' -in $Feature) {
            $regPath = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsAI'

            if ($PSCmdlet.ShouldProcess('Windows Recall', 'Disable via registry policies')) {
                if (-not (Test-Path -LiteralPath $regPath)) {
                    New-Item -Path $regPath -Force | Out-Null
                }

                Set-ItemProperty -Path $regPath -Name 'DisableAIDataAnalysis' -Value 1 -Type DWord -Force
                Set-ItemProperty -Path $regPath -Name 'DisableRecall'         -Value 1 -Type DWord -Force
                Set-ItemProperty -Path $regPath -Name 'AllowRecallEnablement' -Value 0 -Type DWord -Force

                Write-Verbose 'Recall disabled via registry policies.'
            }

            # Disable Recall-related service
            if ($PSCmdlet.ShouldProcess('ScreenshotIndexerService', 'Stop and disable service')) {
                $svc = Get-Service -Name 'ScreenshotIndexerService' -ErrorAction SilentlyContinue
                if ($svc) {
                    Stop-Service -Name 'ScreenshotIndexerService' -Force -ErrorAction SilentlyContinue
                    Set-Service  -Name 'ScreenshotIndexerService' -StartupType Disabled -ErrorAction SilentlyContinue
                    Write-Verbose 'ScreenshotIndexerService stopped and disabled.'
                }
                else {
                    Write-Verbose 'ScreenshotIndexerService not found (may not exist on this build).'
                }
            }

            # Disable Recall-related scheduled tasks
            if ($PSCmdlet.ShouldProcess('Recall Scheduled Tasks', 'Disable AI snapshot tasks')) {
                $recallTasks = Get-ScheduledTask -TaskPath '\Microsoft\Windows\WindowsAI\' -ErrorAction SilentlyContinue |
                    Where-Object { $_.TaskName -match 'Recall|Snapshot|ScreenshotIndex' }

                foreach ($task in $recallTasks) {
                    Disable-ScheduledTask -InputObject $task -ErrorAction SilentlyContinue | Out-Null
                    Write-Verbose "Disabled scheduled task: $($task.TaskName)"
                }
            }

            Write-WinslopFixLog -Message 'Windows Recall disabled (registry, service, tasks).' -EventId 4000

            $results.Add([PSCustomObject]@{
                Feature = 'Recall'
                Action  = 'Disabled'
                Details = 'Registry policies set, ScreenshotIndexerService disabled, scheduled tasks disabled'
            })
        }

        # --- Click to Do ---
        if ('ClickToDo' -in $Feature) {
            $regPath = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsAI'

            if ($PSCmdlet.ShouldProcess('Click to Do', 'Disable via registry policy')) {
                if (-not (Test-Path -LiteralPath $regPath)) {
                    New-Item -Path $regPath -Force | Out-Null
                }

                Set-ItemProperty -Path $regPath -Name 'DisableClickToDo' -Value 1 -Type DWord -Force
                Write-Verbose 'Click to Do disabled via registry policy.'
            }

            Write-WinslopFixLog -Message 'Click to Do disabled via registry policy.' -EventId 4000

            $results.Add([PSCustomObject]@{
                Feature = 'ClickToDo'
                Action  = 'Disabled'
                Details = 'Registry policy set: DisableClickToDo = 1'
            })
        }

        # --- Windows AI Fabric Service ---
        if ('WindowsAI' -in $Feature) {
            if ($PSCmdlet.ShouldProcess('WSAIFabricSvc', 'Stop and disable Windows AI Fabric Service')) {
                $svc = Get-Service -Name 'WSAIFabricSvc' -ErrorAction SilentlyContinue
                if ($svc) {
                    Stop-Service -Name 'WSAIFabricSvc' -Force -ErrorAction SilentlyContinue
                    Set-Service  -Name 'WSAIFabricSvc' -StartupType Disabled -ErrorAction SilentlyContinue
                    Write-Verbose 'WSAIFabricSvc stopped and disabled.'
                }
                else {
                    Write-Verbose 'WSAIFabricSvc not found (may not exist on this build).'
                }
            }

            # Disable all Windows AI scheduled tasks
            if ($PSCmdlet.ShouldProcess('Windows AI Scheduled Tasks', 'Disable all AI tasks')) {
                $aiTasks = Get-ScheduledTask -TaskPath '\Microsoft\Windows\WindowsAI\' -ErrorAction SilentlyContinue

                foreach ($task in $aiTasks) {
                    Disable-ScheduledTask -InputObject $task -ErrorAction SilentlyContinue | Out-Null
                    Write-Verbose "Disabled scheduled task: $($task.TaskName)"
                }
            }

            Write-WinslopFixLog -Message 'Windows AI Fabric Service disabled (service, scheduled tasks).' -EventId 4000

            $results.Add([PSCustomObject]@{
                Feature = 'WindowsAI'
                Action  = 'Disabled'
                Details = 'WSAIFabricSvc disabled, all WindowsAI scheduled tasks disabled'
            })
        }

        return $results
    }
}