public/Watch-LimitFileSize.ps1

function Watch-LimitFileSize {
    <#
    .SYNOPSIS
        Creates or updates a scheduled task to monitor one or more files.

    .DESCRIPTION
        This function creates a Windows scheduled task named "WatchLimitFileSize" that runs the Set-LimitFileSize cmdlet on one or more specified paths. It also applies strict ACLs to these files/folders if the Set-RestrictiveACL module is available. The task is started immediately after being created or updated.

    .PARAMETER Path
        Array of strings containing one or more file or folder paths to monitor. Examples: 'C:\logs\app.log', 'D:\data\config.txt'.

    .PARAMETER MaxSize
        The maximum size the file is allowed to reach before triggering a trimming operation.

        The value must be a number followed optionally by a unit :
        - Use "Ko" for kilooctets (e.g., "100000Ko")
        - Use "Mo" for megaoctets (e.g., "150Mo")
        - If no unit is specified, kilooctets are assumed by default (e.g., "200" means "200Ko").

        Default: "256Ko"

    .PARAMETER VerboseLevel
        Controls the script's verbosity level :
        - "Disabled" : no console output.
        - "Normal" : minimal output.
        - "Debug" : displays details such as initial and final file size.

    .EXAMPLE
        Watch-LimitFileSize -Path "C:\Logs\app.log"

        Creates the scheduled task to monitor a single file.

    .EXAMPLE
        Watch-LimitFileSize -Path "C:\Logs\app1.log", "C:\Logs\app2.log"

        Creates the scheduled task to monitor multiple files.

    .NOTES
        Version : 1.0.0
        Author : Frederic PETIT
        Created : 2025-05-22
        Revised : 2025-05-31

        Compatibility: PowerShell 5+
    #>


    [CmdletBinding(SupportsShouldProcess = $true)]
    Param (
        [Parameter(Mandatory=$true)][string[]]$Path,
        [Parameter(Mandatory=$false)][string]$MaxSize = "256Ko",
        [Parameter(Mandatory=$false)][ValidateSet("Disabled", "Debug")][string]$VerboseLevel = "Disabled"
    )

    # Définition de la tâche.
    $Task = @{
        Name = "WatchLimitFileSize"
        Path = "$env:windir\System32\Tasks"
        Xml = @"
<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.4" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
    <RegistrationInfo>
        <Date>2025-04-04T00:00:00</Date>
        <Author>Administrateur</Author>
        <URI>\WatchLimitFileSize</URI>
    </RegistrationInfo>
    <Triggers>
        <BootTrigger>
            <Enabled>true</Enabled>
        </BootTrigger>
        <TimeTrigger>
            <StartBoundary>2025-01-01T07:00:00</StartBoundary>
            <Enabled>true</Enabled>
        </TimeTrigger>
    </Triggers>
    <Principals>
        <Principal id="Author">
            <UserId>S-1-5-18</UserId>
            <RunLevel>HighestAvailable</RunLevel>
        </Principal>
    </Principals>
    <Settings>
        <MultipleInstancesPolicy>Queue</MultipleInstancesPolicy>
        <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
        <StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
        <AllowHardTerminate>true</AllowHardTerminate>
        <StartWhenAvailable>false</StartWhenAvailable>
        <RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
        <IdleSettings>
            <StopOnIdleEnd>true</StopOnIdleEnd>
            <RestartOnIdle>false</RestartOnIdle>
        </IdleSettings>
        <AllowStartOnDemand>true</AllowStartOnDemand>
        <Enabled>true</Enabled>
        <Hidden>false</Hidden>
        <RunOnlyIfIdle>false</RunOnlyIfIdle>
        <DisallowStartOnRemoteAppSession>false</DisallowStartOnRemoteAppSession>
        <UseUnifiedSchedulingEngine>true</UseUnifiedSchedulingEngine>
        <WakeToRun>true</WakeToRun>
        <ExecutionTimeLimit>PT5M</ExecutionTimeLimit>
        <Priority>7</Priority>
    </Settings>
</Task>
"@

    }

    # Convertir les chemins bruts en chemins absolus, pour éviter les erreurs de contexte.
    try {
        $ResolvedPaths = Resolve-Path -LiteralPath $Path | Select-Object -ExpandProperty Path;
    } catch {
        throw "Error resolving paths : $_";
    }

    # Préparer chaque chemin entre quotes pour usage inline dans un tableau PowerShell.
    $joined = ($ResolvedPaths | ForEach-Object { "'$_'" }) -join ',';

    # Créer une commande complète qui appelle Set-LimitFileSize avec les bons chemins.
    $cmd = "Import-Module LimitFileSize; Set-LimitFileSize -Path @($joined) -MaxSize $MaxSize";
    $argList = "-ExecutionPolicy Bypass -Command `"$cmd`"";

    # Enregistrer ou écraser la tâche planifiée, puis remplacer son action par celle attendue.
    try {
        $RegisteredTask = Register-ScheduledTask -TaskName $Task.Name -Xml $Task.Xml -Force;
    } catch {
        throw "Error registering task : $_";
    }
    $Definition = $RegisteredTask.Definition;
    $Definition.Actions.Clear();
    $Definition.Actions.Add((New-ScheduledTaskAction -Execute 'powershell.exe' -Argument $argList));
    $RegisteredTask.RegisterChanges();

    # Appliquer les ACL strictes sur chaque chemin, si la commande est disponible.
    if (Get-Command -Name Set-RestrictiveACL -ErrorAction SilentlyContinue) {
        foreach ($resolved in $ResolvedPaths) {
            try {
                Set-RestrictiveACL -Path $resolved;
            } catch {
                if ($VerboseLevel -eq "Debug") {
                    Write-Warning "Unable to perform Set-RestrictiveACL on '$resolved' : $_";
                }
            }
        }
    }

    # Vérifier que la tâche a bien été enregistrée puis la démarrer immédiatement.
    try {
        if (Check-ScheduledTask -Name $Task.Name) {
            if ($VerboseLevel -eq "Debug") {
                Write-Host "Task '$Task.Name' OK" -ForegroundColor Green;
            }
            try {
                Start-ScheduledTask -TaskName $Task.Name;
                if ($VerboseLevel -eq "Debug") {
                    Write-Host "Task '$Task.Name' EXEC." -ForegroundColor Green;
                }
            } catch {
                if ($VerboseLevel -eq "Debug") {
                    Write-Warning "Impossible to start '$($Task.Name)' : $_";
                }
            }
        } else {
            if ($VerboseLevel -eq "Debug") {
                Write-Warning "Task '$($Task.Name)' not found after creation.";
            }
        }
    } catch {
        if ($VerboseLevel -eq "Debug") {
            Write-Warning "Task '$($Task.Name)' verification failed : $_";
        }
    }
}