(1) 安裝 Node.js
a. 請到 https://nodejs.org/en/ 下載 Node.js 安裝, 若已經有 Node.js 環境 , 可以忽略此步驟 (檢查 Node.js 版本, 可以使用 node --version 命令)
(2) 安裝 TFS 延伸套件
請從命令提示執行以下命令安裝 TFS 延伸套件
npm install -g tfx-cli
(1) 從命令提示 建立一個目錄存放 Extension
md c:\temp\tfs-extension
(2) 使用 VS Code 建立一下的檔案結構
a. Task 目錄 - 存放 Task Script 與內容
(a) icon.png - task 的 icon (32x32)
(b) task.json - task 的 manifest 檔案
(c) task.ps1 - 實際執行的 task PowerShell script
b. icon128.png - TFS extension 列表的 icon (128x128)
c. icon512.png - Extension detail 的 Icon (512x512)
d. overview.md - Extension 詳細介紹的說明 (Markdown格式)
e. vss-extension.json - TFS extension 打包時的延伸檔
a. id: guid 作為 task 的識別
b. name: Task 名稱
c. friendlyName: 好辨識的名稱
d. author: 作者名稱, 作者名稱必須要註冊於 MarketPlace 中
e. category: 顯示於 Task 類別
f. version: 定義版本資訊
g. instanceNameFormat: 初始的 task 名稱
h. inputs: 參數定義
i. execution: 執行方式
{
"id": "7AE8DD31-8197-4C6E-B3A5-5D2052CFA59F",
"name": "BackupFilesViaPSSession",
"friendlyName": "Backup Files via PS Session",
"description": "Backup files using a Powershell Session.",
"author": "SamLin",
"helpMarkDown": "",
"category": "Utility",
"visibility": [
"Build",
"Release"
],
"demands": [
"DotNetFramework"
],
"version": {
"Major": "0",
"Minor": "2",
"Patch": "19"
},
"minimumAgentVersion": "1.83.0",
"instanceNameFormat": "Powershell Backup files to $(targetpath)",
"groups": [],
"inputs": [
{
"name": "sourcepath",
"type": "string",
"label": "Source Path",
"defaultValue": "",
"required": true,
"helpMarkDown": "A local source path on the remote server."
},
{
"name": "targetpath",
"type": "string",
"label": "Target Path",
"defaultValue": "",
"required": true,
"helpMarkDown": "A local target path on the remote server."
},
{
"name": "backupname",
"type": "string",
"label": "Backup Name",
"defaultValue": "",
"required": true,
"helpMarkDown": "A backup name will append with date(yyyyMMdd).zip file name."
},
{
"name": "server",
"type": "string",
"label": "Remote Machine",
"defaultValue": "",
"required": true,
"helpMarkDown": "FQDN of the remote machine you want to reach (or the IP Address)."
}
],
"execution": {
"PowerShell": {
"target": "$(currentDirectory)\\task.ps1",
"argumentFormat": "",
"workingDirectory": "$(currentDirectory)"
}
}
}
以下範例為遠端備份檔案 script 請自行修改為需要的 script 內容
param (
[string] $sourcepath, # 來源端路徑
[string] $targetpath, # 備份目標路徑
[string] $backupname, # 備份名稱 (將會以備份名稱_yyyyMMdd.zip 為備份檔案名稱)
[string] $server # 遠端主機名稱 (需支援並開啟 PSRemoting)
)
Write-Host "Entering script task.ps1";
Write-Verbose "[server] --> [$server]" -Verbose;
Write-Verbose "[sourcepath] --> [$sourcepath]" -Verbose;
Write-Verbose "[targetpath] --> [$targetpath]" -Verbose;
Write-Verbose "[backupname] --> [$backupname]" -Verbose;
### Validates all paths ###
function ValidatePath ([string]$type, [string]$path) {
Write-Host "Validating $type Path variable.";
if (-not $path.EndsWith("\")) { $path = "$path\"; }
Write-Host "$type Path is $path.";
return $path;
}
$sourcepath = ValidatePath -type "Source" -path $sourcepath;
$targetpath = ValidatePath -type "Target" -path $targetpath;
[System.Management.Automation.Runspaces.PSSession] $session = $null;
$sc = {
Add-Type -AssemblyName System.IO.Compression.FileSystem
$destination = $args[1] + $args[2] + "_" + $(Get-Date -Format 'yyyyMMdd') + ".zip"
if(Test-Path $destination)
{
# 備份目的檔案存在, 移除檔案
Write-Host "Remove destination file..."
Remove-Item $destination
}
if(-Not(Test-Path $args[1]))
{
Write-Host "Create destination folder..."
New-Item -Path $args[1] -ItemType Directory
}
if(Test-Path $args[0])
{
# 備份壓縮原始檔案, 備份完成後移除原始檔案
Write-Host "Backup source files to destination with [$($args[2])_$(Get-Date -Format 'yyyyMMdd').zip] name..."
[IO.Compression.ZipFile]::CreateFromDirectory($args[0], $destination)
Write-Host "Delete source files..."
Remove-Item $args[0] -Recurse -Confirm:$false
}
}
Try
{
$session = New-PSSession -ComputerName $server
Write-Host "Backing up files via remote session.";
Invoke-Command -Session $session -ScriptBlock $sc -ArgumentList $sourcepath, $targetpath, $backupname
}
Catch
{
Write-Host;
Write-Error $_;
}
Finally
{
Write-Host "Closing Powershell remote session on $server.";
if ($null -ne $session) { $session | Disconnect-PSSession | Remove-PSSession };
}
Write-Host "Leaving script task.ps1";
a. version: 版本號
b. name: Extension 顯示名稱
c. publisher: 發行者 (需註冊於 MarketPlace)
d. icon: 檔案名稱定義
e. content: 說明檔
f. files: task 檔案路徑
{
"manifestVersion": 1,
"id": "backupfilesviapssession-task",
"version": "0.1.19",
"name": "Backup Files via PS Session Task",
"publisher": "SamLin",
"targets": [
{
"id": "Microsoft.VisualStudio.Services"
}
],
"description": "Backup Files via PS Session Task for TFS",
"icons": {
"default": "icon128.png",
"large": "icon512.png"
},
"categories": [
"Build and release"
],
"tags": [
"utility",
"tasks"
],
"screenshots": [],
"content": {
"details": {
"path": "overview.md"
}
},
"links": {
"getstarted": {
"uri": "https://www.anisv.com"
}
},
"branding": {
"color": "black",
"theme": "dark"
},
"galleryFlags": [
"Public"
],
"scopes": [
"vso.build_execute",
"vso.serviceendpoint_manage"
],
"files": [
{
"path": "Task"
}
],
"contributions": [
{
"id": "backupfilesviapssession-task",
"type": "ms.vss-distributed-task.task",
"targets": [
"ms.vss-distributed-task.tasks"
],
"properties": {
"name": "Task"
}
}
]
}
使用以下的命令將檔案打包
tfx extension create --manifest-globs vss-extension.json
產出檔案格式如下:
a. 請將檔案打包後的檔案 (SamLin.backupfilesviapssession-task-0.1.19.vsix) 複製到 TFS 上
b. 開啟 TFS extension 管理頁面 (http://tfs:8080/tfs/_gallery/manage)
c. 上傳 TFS extension
d. 安裝 Extension 到 Project Collection
(1) 在 Build definition 新增一個 Task, 可以看到 Utility Category 中出現新加入的 Task
(2) 本範例的使用方式:
a. Display name: Task 名稱
b. Source Path: 備份的來源目錄
c. Target Path: 備份的目的目錄
d. Backup Name: 備份名稱
e. Remote Machine: 可以通過 PSRemote 由 Build Agent 連線 PS Remote Session 執行工作的目標主機名稱
(3) 執行結果:
註: 目標主機開啟 PSRemoting 的 PowerShell 語法如下, 其中 TrustedHosts為 Build Agent 所在的主機名稱
Get-Service -Name WinRM
Enable-PSRemoting -Force
winrm s winrm/config/client '@{TrustedHosts="BUILD"}'
winrm quickconfig
Restart-Service -Name WinRM