Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
edf918c
Enable JUnit output for Pester
Aug 18, 2025
92722c4
chore: use plural test result env var
Aug 18, 2025
d22bbd6
Merge pull request #2 from LabVIEW-Community-CI-CD/codex/update-test_…
Aug 18, 2025
d03d0c8
fix: correct evidence directory for report job
Aug 18, 2025
ee069ee
Merge pull request #3 from LabVIEW-Community-CI-CD/codex/fix-evidence…
Aug 18, 2025
47f22d3
chore: skip report on cancellations
Aug 18, 2025
96b35cf
Merge pull request #4 from LabVIEW-Community-CI-CD/codex/adjust-repor…
Aug 18, 2025
0a90427
docs: document runner types
Aug 18, 2025
e8b8cea
Merge pull request #5 from LabVIEW-Community-CI-CD/codex/update-docum…
Aug 18, 2025
661fd65
Update requirements.json
Aug 18, 2025
6f30d63
ci: use preinstalled PowerShell on Windows runners
Aug 18, 2025
a5b7a62
Merge pull request #6 from LabVIEW-Community-CI-CD/codex/refactor-pow…
Aug 18, 2025
d379ba8
Update requirements.json
Aug 18, 2025
6899775
Update requirements.json
Aug 18, 2025
0d61fb7
Use distinct self-hosted Windows runners
Aug 18, 2025
b8b97f0
Merge pull request #7 from LabVIEW-Community-CI-CD/codex/modify-ci-wo…
Aug 18, 2025
3da1a42
Include runner type in CI artifacts
Aug 18, 2025
6e13155
Merge pull request #8 from LabVIEW-Community-CI-CD/codex/append-runne…
Aug 18, 2025
62d98ea
feat: split self-hosted Windows runners
Aug 18, 2025
3472186
Merge pull request #9 from LabVIEW-Community-CI-CD/codex/restructure-…
Aug 18, 2025
32957be
Rename missing-in-project arch input
Aug 18, 2025
9bd260b
Merge pull request #10 from LabVIEW-Community-CI-CD/codex/rename-arch…
Aug 18, 2025
ba6b4ec
chore: regenerate dispatcher registry
Aug 18, 2025
6a8b366
Merge pull request #11 from LabVIEW-Community-CI-CD/codex/regenerate-…
Aug 18, 2025
313bb36
Standardize PowerShell error handling
Aug 18, 2025
228bbcc
Merge pull request #12 from LabVIEW-Community-CI-CD/codex/standardize…
Aug 18, 2025
396f2bb
test: expand dispatcher args input tests
Aug 18, 2025
8068a1a
Merge pull request #13 from LabVIEW-Community-CI-CD/codex/add-tests-f…
Aug 18, 2025
7dc212b
Document relative path normalization
Aug 18, 2025
e4e76b8
Merge pull request #14 from LabVIEW-Community-CI-CD/codex/normalize-r…
Aug 18, 2025
ae75ca3
docs: add environment setup guide
Aug 19, 2025
c0d7fc8
Fix dispatcher test suite
Aug 19, 2025
6408611
Merge pull request #16 from LabVIEW-Community-CI-CD/codex/fix-failing…
Aug 19, 2025
fb4cde3
Merge pull request #15 from LabVIEW-Community-CI-CD/codex/update-setu…
Aug 19, 2025
6049515
feat: allow suppressing unknown parameter warnings
Aug 19, 2025
efb0e6b
Merge pull request #17 from LabVIEW-Community-CI-CD/codex/add-nowarn-…
Aug 19, 2025
d67df01
test: silence filter-args warnings
Aug 19, 2025
05fc498
Merge pull request #18 from LabVIEW-Community-CI-CD/codex/suppress-wa…
Aug 19, 2025
a13c2ec
chore: remove placeholder test
Aug 19, 2025
785c13a
Merge pull request #19 from LabVIEW-Community-CI-CD/codex/decide-on-t…
Aug 19, 2025
0a2e45b
test: verify FailOnUnknown behavior
Aug 19, 2025
ddf0379
Merge pull request #20 from LabVIEW-Community-CI-CD/codex/add-failonu…
Aug 19, 2025
d466bde
Merge pull request #1 from LabVIEW-Community-CI-CD/codex/update-ci-wo…
Aug 19, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/actionlint.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
self-hosted-runner:
labels:
- icon-editor-windows
- self-hosted-windows-lv
31 changes: 18 additions & 13 deletions .github/workflows/ci.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
{
"run": "npm run generate:summary",
"env": {
"TEST_RESULTS_GLOB": "test-results/*junit*.xml"
"TEST_RESULTS_GLOBS": "test-results/*junit*.xml"
}
},
{
Expand Down Expand Up @@ -83,12 +83,17 @@
{
"os": "ubuntu-24.04",
"runs-on": "ubuntu-24.04",
"runner_type": "default"
"runner_type": "linux"
},
{
"os": "windows-latest",
"runs-on": "windows-latest",
"os": "self-hosted-windows-lv",
"runs-on": "self-hosted-windows-lv",
"runner_type": "integration"
},
{
"os": "self-hosted-windows-lv",
"runs-on": "self-hosted-windows-lv",
"runner_type": "default"
}
]
}
Expand All @@ -102,22 +107,22 @@
"uses": "actions/checkout@v4"
},
{
"name": "Install PowerShell 7.5.1",
"if": "matrix.os == 'windows-latest'",
"name": "Ensure PowerShell 7.5.1",
"if": "matrix.runner_type != 'linux'",
"shell": "pwsh",
"run": "$expectedBuild = '10.0.20348'\n$build = (Get-ComputerInfo).OsVersion\nif ($build -ne $expectedBuild) {\n throw \"Unexpected OS build: $build\"\n}\n$msiUrl = 'https://github.com/PowerShell/PowerShell/releases/download/v7.5.1/PowerShell-7.5.1-win-x64.msi'\n$msiPath = Join-Path $env:RUNNER_TEMP 'PowerShell-7.5.1-win-x64.msi'\nInvoke-WebRequest -Uri $msiUrl -OutFile $msiPath\n$expectedHash = 'b110eccaf55bb53ae5e6b6de478587ed8203570b0bda9bd374a0998e24d4033a'\n$actualHash = (Get-FileHash $msiPath -Algorithm SHA256).Hash\nif ($actualHash -ne $expectedHash) {\n throw \"SHA256 mismatch: $actualHash\"\n}\nStart-Process msiexec -Wait -ArgumentList '/i', $msiPath, '/qn', 'ADD_PATH=1'\n$version = (pwsh --version).Trim() -replace '^PowerShell '\nif ($version -ne '7.5.1') {\n throw \"PowerShell version $version is not 7.5.1\"\n}\n"
"run": "$required = [Version]'7.5.1'\nif ($PSVersionTable.PSVersion -lt $required) {\n $msiUrl = 'https://github.com/PowerShell/PowerShell/releases/download/v7.5.1/PowerShell-7.5.1-win-x64.msi'\n $msiPath = Join-Path $env:RUNNER_TEMP 'PowerShell-7.5.1-win-x64.msi'\n Invoke-WebRequest -Uri $msiUrl -OutFile $msiPath\n $expectedHash = 'b110eccaf55bb53ae5e6b6de478587ed8203570b0bda9bd374a0998e24d4033a'\n $actualHash = (Get-FileHash $msiPath -Algorithm SHA256).Hash\n if ($actualHash -ne $expectedHash) {\n throw \"SHA256 mismatch: $actualHash\"\n }\n Start-Process msiexec -Wait -ArgumentList '/i', $msiPath, '/qn', 'ADD_PATH=1'\n}\n$version = (pwsh --version).Trim() -replace '^PowerShell '\nif ([Version]$version -lt $required) {\n throw \"PowerShell version $version is less than $required\"\n}\n"
},
{
"name": "Capture setup info",
"shell": "pwsh",
"run": "$data = [ordered]@{\n 'Current runner version' = $env:RUNNER_VERSION\n 'Runner Image' = $env:ImageOS\n 'ImageVersion' = $env:ImageVersion\n 'RUNNER_NAME' = $env:RUNNER_NAME\n 'RUNNER_OS' = $env:RUNNER_OS\n 'RUNNER_ARCH' = $env:RUNNER_ARCH\n}\n$file = \"setup-info-${{ matrix.os }}.md\"\n\"was captured from the set up job.\" | Out-File -FilePath $file -Encoding utf8\nforeach ($k in $data.Keys) {\n if ($data[$k]) {\n \"${k}: $($data[$k])\" | Out-File -FilePath $file -Encoding utf8 -Append\n }\n}\n"
"run": "$data = [ordered]@{\n 'Current runner version' = $env:RUNNER_VERSION\n 'Runner Image' = $env:ImageOS\n 'ImageVersion' = $env:ImageVersion\n 'RUNNER_NAME' = $env:RUNNER_NAME\n 'RUNNER_OS' = $env:RUNNER_OS\n 'RUNNER_ARCH' = $env:RUNNER_ARCH\n}\n$file = \"setup-info-${{ matrix.os }}-${{ matrix.runner_type }}.md\"\n\"was captured from the set up job.\" | Out-File -FilePath $file -Encoding utf8\nforeach ($k in $data.Keys) {\n if ($data[$k]) {\n \"${k}: $($data[$k])\" | Out-File -FilePath $file -Encoding utf8 -Append\n }\n}\n"
},
{
"uses": "actions/upload-artifact@v4",
"if": "always()",
"with": {
"name": "setup-info-${{ matrix.os }}",
"path": "setup-info-${{ matrix.os }}.md"
"name": "setup-info-${{ matrix.os }}-${{ matrix.runner_type }}",
"path": "setup-info-${{ matrix.os }}-${{ matrix.runner_type }}.md"
}
},
{
Expand All @@ -139,7 +144,7 @@
"uses": "actions/upload-artifact@v4",
"if": "always()",
"with": {
"name": "pester-junit-${{ matrix.os }}",
"name": "pester-junit-${{ matrix.os }}-${{ matrix.runner_type }}",
"path": "pester-results/pester-junit.xml",
"if-no-files-found": "error"
}
Expand All @@ -152,7 +157,7 @@
"ps-ci"
],
"runs-on": "ubuntu-24.04",
"if": "always()",
"if": "(success() || failure()) && !cancelled()",
"steps": [
{
"uses": "actions/checkout@v4"
Expand Down Expand Up @@ -184,7 +189,7 @@
"TEST_RESULTS_GLOBS": "downloaded/test-results/**/*junit*.xml\ndownloaded/pester-junit-*/pester-junit.xml\n",
"REQ_MAPPING_FILE": "requirements.json",
"DISPATCHER_REGISTRY": "dispatchers.json",
"EVIDENCE_DIR": "test-screenshots"
"EVIDENCE_DIR": "downloaded/evidence"
}
},
{
Expand Down
64 changes: 36 additions & 28 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,19 @@ jobs:
- run: npm run derive:registry
- run: npm run generate:summary
env:
TEST_RESULTS_GLOB: test-results/*junit*.xml
TEST_RESULTS_GLOBS: test-results/*junit*.xml
- uses: actions/upload-artifact@v4
if: always()
if: ${{ (success() || failure()) && !cancelled() }}
with:
name: traceability
path: ${{ env.ARTIFACT_DIR }}/traceability.*
- uses: actions/upload-artifact@v4
if: always()
if: ${{ (success() || failure()) && !cancelled() }}
with:
name: action-docs
path: ${{ env.ARTIFACT_DIR }}/action-docs.*
- uses: actions/upload-artifact@v4
if: always()
if: ${{ (success() || failure()) && !cancelled() }}
with:
name: evidence
path: ${{ env.ARTIFACT_DIR }}/evidence/**
Expand All @@ -49,31 +49,37 @@ jobs:
include:
- os: ubuntu-24.04
runs-on: ubuntu-24.04
runner_type: default
- os: windows-latest
runs-on: windows-latest
runner_type: linux
- os: self-hosted-windows-lv
runs-on: self-hosted-windows-lv
runner_type: integration
- os: self-hosted-windows-lv
runs-on: self-hosted-windows-lv
runner_type: default
runs-on: ${{ matrix.runs-on }}
env:
RUNNER_TYPE: ${{ matrix.runner_type }}
steps:
- uses: actions/checkout@v4
- name: Install PowerShell 7.5.1
if: matrix.os == 'windows-latest'
- name: Ensure PowerShell 7.5.1
if: matrix.runner_type != 'linux'
shell: pwsh
run: |
$msiUrl = 'https://github.com/PowerShell/PowerShell/releases/download/v7.5.1/PowerShell-7.5.1-win-x64.msi'
$msiPath = Join-Path $env:RUNNER_TEMP 'PowerShell-7.5.1-win-x64.msi'
Invoke-WebRequest -Uri $msiUrl -OutFile $msiPath
$expectedHash = 'b110eccaf55bb53ae5e6b6de478587ed8203570b0bda9bd374a0998e24d4033a'
$actualHash = (Get-FileHash $msiPath -Algorithm SHA256).Hash
if ($actualHash -ne $expectedHash) {
throw "SHA256 mismatch: $actualHash"
$required = [Version]'7.5.1'
if ($PSVersionTable.PSVersion -lt $required) {
$msiUrl = 'https://github.com/PowerShell/PowerShell/releases/download/v7.5.1/PowerShell-7.5.1-win-x64.msi'
$msiPath = Join-Path $env:RUNNER_TEMP 'PowerShell-7.5.1-win-x64.msi'
Invoke-WebRequest -Uri $msiUrl -OutFile $msiPath
$expectedHash = 'b110eccaf55bb53ae5e6b6de478587ed8203570b0bda9bd374a0998e24d4033a'
$actualHash = (Get-FileHash $msiPath -Algorithm SHA256).Hash
if ($actualHash -ne $expectedHash) {
throw "SHA256 mismatch: $actualHash"
}
Start-Process msiexec -Wait -ArgumentList '/i', $msiPath, '/qn', 'ADD_PATH=1'
}
Start-Process msiexec -Wait -ArgumentList '/i', $msiPath, '/qn', 'ADD_PATH=1'
$version = (pwsh --version).Trim() -replace '^PowerShell '
if ($version -ne '7.5.1') {
throw "PowerShell version $version is not 7.5.1"
if ([Version]$version -lt $required) {
throw "PowerShell version $version is less than $required"
}
- name: Capture setup info
shell: pwsh
Expand All @@ -86,18 +92,18 @@ jobs:
'RUNNER_OS' = $env:RUNNER_OS
'RUNNER_ARCH' = $env:RUNNER_ARCH
}
$file = "setup-info-${{ matrix.os }}.md"
$file = "setup-info-${{ matrix.os }}-${{ matrix.runner_type }}.md"
"was captured from the set up job." | Out-File -FilePath $file -Encoding utf8
foreach ($k in $data.Keys) {
if ($data[$k]) {
"${k}: $($data[$k])" | Out-File -FilePath $file -Encoding utf8 -Append
}
}
- uses: actions/upload-artifact@v4
if: always()
if: ${{ (success() || failure()) && !cancelled() }}
with:
name: setup-info-${{ matrix.os }}
path: setup-info-${{ matrix.os }}.md
name: setup-info-${{ matrix.os }}-${{ matrix.runner_type }}
path: setup-info-${{ matrix.os }}-${{ matrix.runner_type }}.md
- name: Install Pester
shell: pwsh
run: |
Expand All @@ -112,21 +118,23 @@ jobs:
if (Test-Path "tests/pester") {
$cfg = New-PesterConfiguration
$cfg.Run.Path = './tests/pester'
$cfg.TestResult.Enabled = $false
$cfg.TestResult.Enabled = $true
$cfg.TestResult.OutputFormat = 'JUnitXml'
$cfg.TestResult.OutputPath = 'pester-results/pester-junit.xml'
$cfg.Run.Exit = $true
Invoke-Pester -Configuration $cfg
}
- uses: actions/upload-artifact@v4
if: always()
if: ${{ (success() || failure()) && !cancelled() }}
with:
name: pester-junit-${{ matrix.os }}
name: pester-junit-${{ matrix.os }}-${{ matrix.runner_type }}
path: pester-results/pester-junit.xml
if-no-files-found: error

report:
needs: [node-ci, ps-ci]
runs-on: ubuntu-24.04
if: always()
if: ${{ (success() || failure()) && !cancelled() }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
Expand All @@ -145,5 +153,5 @@ jobs:
downloaded/pester-junit-*/pester-junit.xml
REQ_MAPPING_FILE: requirements.json
DISPATCHER_REGISTRY: dispatchers.json
EVIDENCE_DIR: test-screenshots
EVIDENCE_DIR: downloaded/evidence
- run: npx tsx scripts/print-pester-traceability.ts >> "$GITHUB_STEP_SUMMARY"
2 changes: 1 addition & 1 deletion .github/workflows/missing-in-project-self-hosted.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"uses": "./missing-in-project/action.yml",
"with": {
"lv_version": "2021",
"arch": "64",
"supported_bitness": "64",
"project_file": "scripts/missing-in-project/Missing in Project.lvproj",
"relative_path": "scripts/missing-in-project"
}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/missing-in-project-self-hosted.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
uses: ./missing-in-project/action.yml
with:
lv_version: '2021'
arch: '64'
supported_bitness: '64'
project_file: 'scripts/missing-in-project/Missing in Project.lvproj'
relative_path: 'scripts/missing-in-project'
- name: Upload missing findings
Expand Down
7 changes: 7 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
## Environment Setup
- Run `apt-get update && apt-get install -y apt-utils` to ensure required APT utilities are available.
- Ensure Node.js 24 or newer is installed (e.g. via the NodeSource setup script).
- Verify with `node --version`.
- Install `actionlint` and ensure it is on your `PATH`:
- `go install github.com/rhysd/actionlint/cmd/actionlint@latest`
- Verify with `actionlint -version`.
- Ensure PowerShell 7.5.1 is installed and accessible.
- Verify with `pwsh --version`.
- Linux runners rely on preinstalled `pwsh`.
- On Windows Server 2022 (build 10.0.20348), download the MSI and verify its SHA256 checksum before installing:

Expand All @@ -18,6 +21,10 @@
Remove-Item pwsh.msi
```
- PowerShell 7.5.1 includes native YAML support; external modules such as `powershell-yaml` are no longer required.
- Install NI LabVIEW's command-line interface (g-cli) on Windows runners and ensure it is accessible.
- Verify with `g-cli --version` or `& 'C:\\Program Files\\G-CLI\\bin\\g-cli.exe' --version`.
- Optional: set `LABVIEW_ICON_EDITOR_PATH` if a custom icon editor location is required.
- Verify with `echo $LABVIEW_ICON_EDITOR_PATH` (or `$env:LABVIEW_ICON_EDITOR_PATH` in PowerShell).

## Testing
- Run `npm run check:node` to verify Node.js satisfies the required version.
Expand Down
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ For setup and action reference, see the [documentation](docs/index.md). The [qui
- NI LabVIEW with command-line interface support (g-cli) for LabVIEW-based actions
- Supported platforms: Windows for LabVIEW tasks; PowerShell-only scripts also run on macOS and Linux

See [Environment Setup](docs/environment-setup.md) for installation steps and commands to verify each dependency.

## GitHub Action usage

```yaml
Expand Down Expand Up @@ -111,6 +113,12 @@ Alternatively, load arguments from a JSON file:
pwsh ./actions/Invoke-OSAction.ps1 -ActionName run-unit-tests -ArgsFile ./config/run-tests.json
```

By default the dispatcher ignores unknown parameters and emits a warning. Add `-FailOnUnknown` to treat unexpected parameters as errors:

```powershell
pwsh ./actions/Invoke-OSAction.ps1 -ActionName run-unit-tests -ArgsJson $json -FailOnUnknown
```

### Discovering actions

List all available actions:
Expand All @@ -125,6 +133,10 @@ Get details about a specific action:
pwsh actions/Invoke-OSAction.ps1 -Describe run-unit-tests
```

## Runner Types

Workflows distinguish between standard GitHub-hosted images and integration runners with preinstalled tooling. See [docs/runner-types.md](docs/runner-types.md) for a detailed comparison.

## Testing

Run the JavaScript tests with:
Expand Down
49 changes: 45 additions & 4 deletions actions/Invoke-OSAction.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ param(
[Parameter()] [ValidateSet('ERROR','WARN','INFO','DEBUG')] [string] $LogLevel = 'INFO',
[switch] $DryRun,
[switch] $ListActions,
[switch] $FailOnUnknown,
[string] $Describe
)

Expand Down Expand Up @@ -97,8 +98,15 @@ function Show-Description([string]$Name) {
# InputArgs: Hashtable of supplied arguments.
# FuncName: Target dispatcher function name.
# ActionNameForWarn: Action name used when emitting warnings.
# ReturnUnknownParams: If set, returns unknown parameters as well.
function Filter-Args([hashtable]$InputArgs, [string]$FuncName, [string]$ActionNameForWarn, [switch]$ReturnUnknownParams) {
# ReturnUnknownParams: If set, returns unknown parameters and suppresses warnings.
# NoWarn: Suppresses warnings for unknown parameters without returning them.
function Filter-Args(
[hashtable]$InputArgs,
[string]$FuncName,
[string]$ActionNameForWarn,
[switch]$ReturnUnknownParams,
[switch]$NoWarn
) {
$cmd = Get-Command $FuncName -ErrorAction Stop

# Map each alias to its canonical parameter name for the target function
Expand All @@ -124,14 +132,35 @@ function Filter-Args([hashtable]$InputArgs, [string]$FuncName, [string]$ActionNa
$msg = $null
if ($unknown.Count) {
$msg = "Ignored unknown parameters for '$ActionNameForWarn': $($unknown -join ', ')"
Write-Warning $msg
if (-not $NoWarn -and -not $ReturnUnknownParams) {
Write-Warning $msg
}
}
if ($ReturnUnknownParams) {
return [pscustomobject]@{ Args = $filtered; UnknownParams = $msg }
}
return $filtered
}

# Normalizes a RelativePath value against an optional base directory.
# RelativePath: Path to normalize.
# BaseDirectory: Directory used to resolve the relative path. Defaults to the current location.
function Normalize-RelativePath {
param(
[Parameter(Mandatory)] [string] $RelativePath,
[string] $BaseDirectory
)
$base = if ($BaseDirectory) {
[System.IO.Path]::GetFullPath($BaseDirectory)
} else {
[System.IO.Directory]::GetCurrentDirectory()
}
$combined = [System.IO.Path]::Combine($base, $RelativePath)
$full = [System.IO.Path]::GetFullPath($combined)
$relative = [System.IO.Path]::GetRelativePath($base, $full)
return [System.IO.Path]::TrimEndingDirectorySeparator($relative)
}

try {
# Discovery short-circuits
if ($ListActions) { Show-List; exit 0 }
Expand Down Expand Up @@ -198,7 +227,19 @@ try {
Set-LogLevel -Level $LogLevel

# Only pass parameters that the adapter actually accepts
$argsHash = Filter-Args -InputArgs $argsHash -FuncName $funcName -ActionNameForWarn $key
$filterResult = Filter-Args -InputArgs $argsHash -FuncName $funcName -ActionNameForWarn $key -ReturnUnknownParams
$argsHash = $filterResult.Args
if ($filterResult.UnknownParams) {
if ($FailOnUnknown) {
throw $filterResult.UnknownParams
} else {
Write-Warning $filterResult.UnknownParams
}
}

if ($argsHash.ContainsKey('RelativePath')) {
$argsHash['RelativePath'] = Normalize-RelativePath -RelativePath $argsHash['RelativePath'] -BaseDirectory $WorkingDirectory
}

if ($WorkingDirectory) { Push-Location -Path $WorkingDirectory }
try {
Expand Down
Loading
Loading