deadlydog
deadlydog

Reputation: 24424

Azure DevOps custom build task extension cannot find PowerShell VstsTaskSdk.psd1 when target entry file is not in root directory

I built the Wait Azure DevOps build/release task extension a while ago, and recently it started reporting the following warning when it runs:

[warning]Task 'Wait' (1.2.3) is using deprecated task execution handler. The task should use the supported task-lib: https://aka.ms/tasklib

So, following that link to the Azure Pipelines Task SDK GitHub repo and then drilling into the Consuming the PowerShell API SDK link it looks like I need to update my extension from the old PowerShell execution handler to the new PowerShell3 execution handler in my task.json file, so I made that change and the code now looks like this:

  "execution": {
    "PowerShell3": {
      "target": "$(currentDirectory)/Code/Wait.ps1",
      "workingDirectory": "$(currentDirectory)"
    }
  }

Following the instructions on the page, I've done Save-Module -Name VstsTaskSdk -Path .\ to download the SDK module and have committed it to the ps_modules\VstsTaskSdk directory at the root of my extension's task.

However, after building and running the extension on an MS Hosted agent, it gives the error:

[error]File not found: 'D:\a_tasks\Wait_f3e9b3d7-a528-5245-91c7-453406bcb038\1.2.17\Code\ps_modules\VstsTaskSdk\VstsTaskSdk.psd1'

Azure DevOps task output

I noticed that it was looking for the ps_modules directory in the Code directory, so I tried placing it there in my git repo, but that still results in the same error.

I found this very similar StackOverflow question, but the solution for them was to remove the version directory from their hierarchy of ps_modules\[version]\VstsTaskSdk, which I already don't have.

I also found this blog post walking through the process, and it looks like I've done everything correct, but I still get the error.

This is what my file hierarchy looks like:

|-- Wait\ <task root>
  |-- Code\
    |-- Convert-Unit.Tests.ps1
    |-- Convert-Unit.psm1
    |-- Wait.ps1
  |-- ps_modules\
    |-- VstsTaskSdk\
      |-- [All the module files, including VstsTaskSdk.psd1]
  |-- icon.png
  |-- task.json

I was thinking the problem might be that I keep my tasks "business logic code" separated from the "task infrastructure code", by placing it in a Code directory; that is, my task.json file and the Wait.ps1 target entry point file are not in the same directory. Following this assumption I removed the Code directory and dumped all of the files in the root directory, and the error went away (I'm now getting different errors, but it looks to have solved this one).

Any thoughts on what I can do to still have my "business logic code" separated from the "task infrastructure code" when migrating over to the new PowerShell execution handler? I'm not sure how it determines where it should look for the ps_modules directory.

The code is all open source as well, so feel free to look at the repo.

Update

While I was not able to solve the problem of how to have the task.json and target entry point PowerShell script files in separate directories, I was able to make changes so that all of the extension infrastructure code is in the root directory, and the "business logic" code in the Code directory.

As you can see in the repo, I opted to create a task.ps1 file in the tasks root directory, and to use that as the target entry point for the task. Updating to the PowerShell3 execution handler also meant having to update how we retrieve the task inputs, so I'm using the task.ps1 file to get the inputs and then simply call the Code\Wait.ps1 script. This allows me to keep my code nice and isolated, so if Azure DevOps decides to change things up with a new execution handler again, I won't need to touch any of the code in the Code directory, just the task.ps1 file.

Upvotes: 3

Views: 2648

Answers (1)

Mengdi Liang
Mengdi Liang

Reputation: 19026

In fact, I think the solution you were trying, put the extension entry script(task.ps1) at the same level as the SDK packaged folder, is the best choice for you until now.

As the normal compile process, it would find the folder where the .dll files stored automatically from the same folder level when you start the entry script. For Azure Devops, this default folder which used to stored the .dll files is ps_modules. This a default action which as designed.

That's the reason for why you receive the error about the server is looking for the .dll from Code folder. Also, it is why we recommend the developer package the task with SDK as the below layout:

enter image description here


Separate the SDK and script files completely in two folders is not impossible, just if you choose this layout, it can make the file structure very clean, but it will greatly increase the code cost(Use $PSScriptRoot to override all SDK load script), as well as the maintenance cost later.

Create and put the entry script at the same folder level with the SDK folder(ps_modules), then called the function from relevant script files which all stored at same folder, is the best method to keep the files structure clean and maintain the maintainability of the code, also it will not increase the additionally code consumption, which would cause the redundancy of the code increased.

Upvotes: 0

Related Questions