NexthinkApi.psm1
|
using namespace System.Management.Automation class ValidateWritableFolderAttribute : ValidateArgumentsAttribute { hidden [bool] TestWritable([string] $path, [ref] $errorMsg) { # Resolve the path try { $resolved = Convert-Path -LiteralPath $path -ErrorAction Stop } catch { $errorMsg.Value = "Path '$path' does not exist." return $false } # Must be a directory if (-not (Test-Path -LiteralPath $resolved -PathType Container)) { $errorMsg.Value = "Path '$path' is not a directory." return $false } # Try writing a temp file $tmpFile = Join-Path $resolved ".writetest.tmp" try { New-Item -Path $tmpFile -ItemType File -Force -ErrorAction Stop | Out-Null Remove-Item -LiteralPath $tmpFile -Force -ErrorAction Stop } catch { $errorMsg.Value = "Folder '$path' is not writable. Details: $($_.Exception.Message)" return $false } return $true } [void] Validate([object] $arguments, [EngineIntrinsics] $engineIntrinsics) { if ($null -eq $arguments) { throw [ValidationMetadataException]::new("Output folder cannot be null.") } if (-not ($arguments -is [string])) { throw [ValidationMetadataException]::new("Output folder must be a string path.") } $msg = $null if (-not $this.TestWritable([string]$arguments, [ref]$msg)) { throw [ValidationMetadataException]::new($msg) } } } Write-Verbose "Loading module from $PSScriptRoot" # Required dependency modules $requiredModules = 'Logging', 'CredentialManager' $available = Get-Module -ListAvailable -Name $requiredModules $availableNames = $available.Name | Select-Object -Unique $missing = $requiredModules | Where-Object { $_ -notin $availableNames } if ($missing) { $missingList = $missing -join ', ' $msg = @" The following required modules are missing: $missingList Run the following command to install prerequisites: Install-NexthinkApiPrereqs Then import the NexthinkAPI module again. "@ Write-Warning $msg throw "Missing prerequisites: $missingList" } # Optional update check for this module # Controlled by env var: NEXTHINKAPI_SKIP_UPDATECHECK=1 to disable $moduleName = 'NexthinkAPI' if ($env:NEXTHINKAPI_SKIP_UPDATECHECK -ne '1') { try { $currentModule = Get-Module -ListAvailable -Name $moduleName | Sort-Object Version -Descending | Select-Object -First 1 $latestModule = Find-Module -Name $moduleName -Repository PSGallery -ErrorAction Stop if ($currentModule -and $currentModule.Version -lt $latestModule.Version) { Write-Host -NoNewline "The module " Write-Host -NoNewline "'$moduleName'" -ForegroundColor Blue Write-Host -NoNewline " is out of date! The latest version is " Write-Host -NoNewline "'$($latestModule.Version)'." -ForegroundColor Green Write-Host " Please update before running again to avoid any issues." Write-Host -NoNewline " Example: " Write-Host "Update-Module $moduleName -Scope CurrentUser" -ForegroundColor Red } } catch { # Don't break module load if PSGallery is unreachable Write-Verbose "Skipping update check for $moduleName. Reason: $($_.Exception.Message)" } } # Load MAIN config $mainConfigPath = Join-Path -Path $PSScriptRoot -ChildPath 'config\main.json' write-Verbose "Loading main configuration from $mainConfigPath" if (-not (Test-Path -LiteralPath $mainConfigPath)) { $msg = "Unable to locate main configuration file: $mainConfigPath" Write-Error $msg throw $msg } try { $script:MAIN = Get-Content -LiteralPath $mainConfigPath -Raw | ConvertFrom-Json Set-Variable -Name MAIN -Scope Script -Option ReadOnly -Force -Value $script:MAIN } catch { $msg = "Failed to load or parse $mainConfigPath. Details: $($_.Exception.Message)" Write-Error $msg throw $msg } # Dot-source Private and Public functions foreach ($folder in @('Private', 'Public')) { $root = Join-Path -Path $PSScriptRoot -ChildPath $folder if (Test-Path -LiteralPath $root) { Write-Verbose "Processing folder $root" Get-ChildItem -Path $root -Filter *.ps1 -Recurse | Where-Object { $_.Name -notlike '*.Tests.ps1' } | ForEach-Object { Write-Verbose "Dot-sourcing $($_.FullName)" . $_.FullName } } } # Export public functions + MAIN variable $publicFunctions = Get-ChildItem -Path (Join-Path $PSScriptRoot 'Public') -Filter *.ps1 -ErrorAction SilentlyContinue | Select-Object -ExpandProperty BaseName if ($publicFunctions) { Export-ModuleMember -Function $publicFunctions -Variable MAIN } else { Export-ModuleMember -Variable MAIN } |