├── .gitattributes ├── .gitignore ├── GitVersion.yml ├── LICENSE.txt ├── README.md ├── docs ├── assets │ ├── vsts-process-template-management-admin.png │ ├── vsts-process-template-management-export.png │ ├── vsts-process-template-management-publish.png │ └── vsts-process-template-management-zip.png └── index.md ├── images ├── extension-icon.png ├── icon.pdn └── screenshot-01.png ├── mkdocs.yaml ├── tests └── data │ ├── meta-build.json │ └── meta-gitversion.json ├── variabledehydration-task └── v0 │ ├── dehydrate-variables-debug.ps1 │ ├── dehydrate-variables.ps1 │ ├── icon.png │ ├── ps_modules │ └── VstsTaskSdk │ │ ├── FindFunctions.ps1 │ │ ├── InputFunctions.ps1 │ │ ├── LocalizationFunctions.ps1 │ │ ├── LoggingCommandFunctions.ps1 │ │ ├── LongPathFunctions.ps1 │ │ ├── OutFunctions.ps1 │ │ ├── PSGetModuleInfo.xml │ │ ├── ServerOMFunctions.ps1 │ │ ├── Strings │ │ └── resources.resjson │ │ │ ├── de-de │ │ │ └── resources.resjson │ │ │ ├── en-US │ │ │ └── resources.resjson │ │ │ ├── es-es │ │ │ └── resources.resjson │ │ │ ├── fr-fr │ │ │ └── resources.resjson │ │ │ ├── it-IT │ │ │ └── resources.resjson │ │ │ ├── ja-jp │ │ │ └── resources.resjson │ │ │ ├── ko-KR │ │ │ └── resources.resjson │ │ │ ├── ru-RU │ │ │ └── resources.resjson │ │ │ ├── zh-CN │ │ │ └── resources.resjson │ │ │ └── zh-TW │ │ │ └── resources.resjson │ │ ├── ToolFunctions.ps1 │ │ ├── TraceFunctions.ps1 │ │ ├── VstsTaskSdk.psd1 │ │ ├── VstsTaskSdk.psm1 │ │ └── lib.json │ └── task.json ├── variablerehydration-task └── v0 │ ├── icon.png │ ├── ps_modules │ └── VstsTaskSdk │ │ ├── FindFunctions.ps1 │ │ ├── InputFunctions.ps1 │ │ ├── LocalizationFunctions.ps1 │ │ ├── LoggingCommandFunctions.ps1 │ │ ├── LongPathFunctions.ps1 │ │ ├── OutFunctions.ps1 │ │ ├── PSGetModuleInfo.xml │ │ ├── ServerOMFunctions.ps1 │ │ ├── Strings │ │ └── resources.resjson │ │ │ ├── de-de │ │ │ └── resources.resjson │ │ │ ├── en-US │ │ │ └── resources.resjson │ │ │ ├── es-es │ │ │ └── resources.resjson │ │ │ ├── fr-fr │ │ │ └── resources.resjson │ │ │ ├── it-IT │ │ │ └── resources.resjson │ │ │ ├── ja-jp │ │ │ └── resources.resjson │ │ │ ├── ko-KR │ │ │ └── resources.resjson │ │ │ ├── ru-RU │ │ │ └── resources.resjson │ │ │ ├── zh-CN │ │ │ └── resources.resjson │ │ │ └── zh-TW │ │ │ └── resources.resjson │ │ ├── ToolFunctions.ps1 │ │ ├── TraceFunctions.ps1 │ │ ├── VstsTaskSdk.psd1 │ │ ├── VstsTaskSdk.psm1 │ │ └── lib.json │ ├── rehydrate-variables-debug.ps1 │ ├── rehydrate-variables.ps1 │ └── task.json └── vss-extension.json /.gitattributes: -------------------------------------------------------------------------------- 1 | # default behavior to automatically normalize line endings 2 | * text=auto -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.jfm 193 | *.pfx 194 | *.publishsettings 195 | node_modules/ 196 | orleans.codegen.cs 197 | 198 | # Since there are multiple workflows, uncomment next line to ignore bower_components 199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 200 | #bower_components/ 201 | 202 | # RIA/Silverlight projects 203 | Generated_Code/ 204 | 205 | # Backup & report files from converting an old project file 206 | # to a newer Visual Studio version. Backup files are not needed, 207 | # because we have git ;-) 208 | _UpgradeReport_Files/ 209 | Backup*/ 210 | UpgradeLog*.XML 211 | UpgradeLog*.htm 212 | 213 | # SQL Server files 214 | *.mdf 215 | *.ldf 216 | 217 | # Business Intelligence projects 218 | *.rdl.data 219 | *.bim.layout 220 | *.bim_*.settings 221 | 222 | # Microsoft Fakes 223 | FakesAssemblies/ 224 | 225 | # GhostDoc plugin setting file 226 | *.GhostDoc.xml 227 | 228 | # Node.js Tools for Visual Studio 229 | .ntvs_analysis.dat 230 | 231 | # Visual Studio 6 build log 232 | *.plg 233 | 234 | # Visual Studio 6 workspace options file 235 | *.opt 236 | 237 | # Visual Studio LightSwitch build output 238 | **/*.HTMLClient/GeneratedArtifacts 239 | **/*.DesktopClient/GeneratedArtifacts 240 | **/*.DesktopClient/ModelManifest.xml 241 | **/*.Server/GeneratedArtifacts 242 | **/*.Server/ModelManifest.xml 243 | _Pvt_Extensions 244 | 245 | # Paket dependency manager 246 | .paket/paket.exe 247 | paket-files/ 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | # JetBrains Rider 253 | .idea/ 254 | *.sln.iml 255 | 256 | # CodeRush 257 | .cr/ 258 | 259 | # Python Tools for Visual Studio (PTVS) 260 | __pycache__/ 261 | *.pyc -------------------------------------------------------------------------------- /GitVersion.yml: -------------------------------------------------------------------------------- 1 | assembly-versioning-scheme: MajorMinorPatch 2 | mode: ContinuousDeployment 3 | continuous-delivery-fallback-tag: '' 4 | next-version: 0.2.1 5 | branches: 6 | master: 7 | mode: ContinuousDeployment 8 | tag: '' 9 | ignore: 10 | sha: [] -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 naked Agility Limited - Martin Hinshelwood 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Azure DevOps Variable Tools 2 | 3 | Azure DevOps Variable Tools is an extension for Azure Pipleines Build and Azure Pipleines Release that help you make use of your Build variables in your Release workflows. 4 | 5 | Get the [Azure DevOps Variable Tools](https://marketplace.visualstudio.com/items?itemName=nkdagility.variablehydration) extensions for Azure DevOps Services from the Marketplace. 6 | 7 | Learn more about this extension on the wiki! 8 | 9 | ##Tasks included 10 | 11 | - **Variable Save Task** - During your build you can save the variables to a json file stored with your other build assets 12 | - **Variable Load Task** - During your Release you can load the saved variables and gain access to them. 13 | 14 | ##Steps 15 | 16 | After installing the extension, you can add one (or more) of the tasks to a new or existing build definition or release definition 17 | 18 | Full documentation is available on [https://dev.azure.com/nkdagility/Azure-DevOps-Variable-Tools/_wiki/wikis/variable-tools](https://dev.azure.com/nkdagility/Azure-DevOps-Variable-Tools/_wiki/wikis/variable-tools) 19 | 20 | **NOTE: This Task used PowerShell which currently only supports Windows untill [PowerShell Handler to run PS based task on Linux/MacOS agent](https://github.com/Microsoft/vsts-task-lib/issues/314) is resolved to support cross-platform.** 21 | -------------------------------------------------------------------------------- /docs/assets/vsts-process-template-management-admin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkdAgility/azure-devops-variable-tools/cc71f5f1648177772a8bb80473407752c50c0858/docs/assets/vsts-process-template-management-admin.png -------------------------------------------------------------------------------- /docs/assets/vsts-process-template-management-export.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkdAgility/azure-devops-variable-tools/cc71f5f1648177772a8bb80473407752c50c0858/docs/assets/vsts-process-template-management-export.png -------------------------------------------------------------------------------- /docs/assets/vsts-process-template-management-publish.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkdAgility/azure-devops-variable-tools/cc71f5f1648177772a8bb80473407752c50c0858/docs/assets/vsts-process-template-management-publish.png -------------------------------------------------------------------------------- /docs/assets/vsts-process-template-management-zip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkdAgility/azure-devops-variable-tools/cc71f5f1648177772a8bb80473407752c50c0858/docs/assets/vsts-process-template-management-zip.png -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # Azure DevOps Variable Tools 2 | 3 | Azure DevOps Variable Tools is an extesnion for Azure Pipleines Build and Azure Pipleines Release that help you make use of your Build variables in your Release workflows. 4 | 5 | Get the [Azure DevOps Variable Tools](https://marketplace.visualstudio.com/items?itemName=nkdagility.variablehydration) extensions for Azure DevOps Services from the Marketplace. 6 | 7 | Learn more about this extension on the wiki! 8 | 9 | ##Tasks included 10 | 11 | - **Variable Save Task** - During your build you can save the variables to a json file stored with your other build assets 12 | - **Variable Load Task** - During your Release you can load the saved variables and gain access to them. 13 | 14 | ##Steps 15 | 16 | After installing the extension, you can add one (or more) of the tasks to a new or existing build definition or release definition 17 | 18 | Full documentation is available on [https://dev.azure.com/nkdagility/Azure-DevOps-Variable-Tools/_wiki/wikis/variable-tools](https://dev.azure.com/nkdagility/Azure-DevOps-Variable-Tools/_wiki/wikis/variable-tools) 19 | 20 | **NOTE: This Task used PowerShell which currently only supports Windows untill [PowerShell Handler to run PS based task on Linux/MacOS agent](https://github.com/Microsoft/vsts-task-lib/issues/314) is resolved to support cross-platform.** -------------------------------------------------------------------------------- /images/extension-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkdAgility/azure-devops-variable-tools/cc71f5f1648177772a8bb80473407752c50c0858/images/extension-icon.png -------------------------------------------------------------------------------- /images/icon.pdn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkdAgility/azure-devops-variable-tools/cc71f5f1648177772a8bb80473407752c50c0858/images/icon.pdn -------------------------------------------------------------------------------- /images/screenshot-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkdAgility/azure-devops-variable-tools/cc71f5f1648177772a8bb80473407752c50c0858/images/screenshot-01.png -------------------------------------------------------------------------------- /mkdocs.yaml: -------------------------------------------------------------------------------- 1 | site_name: VSTS Variable (de|re)Hydration Tasks 2 | pages: 3 | - Home: index.md 4 | theme: readthedocs 5 | -------------------------------------------------------------------------------- /tests/data/meta-build.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkdAgility/azure-devops-variable-tools/cc71f5f1648177772a8bb80473407752c50c0858/tests/data/meta-build.json -------------------------------------------------------------------------------- /tests/data/meta-gitversion.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkdAgility/azure-devops-variable-tools/cc71f5f1648177772a8bb80473407752c50c0858/tests/data/meta-gitversion.json -------------------------------------------------------------------------------- /variabledehydration-task/v0/dehydrate-variables-debug.ps1: -------------------------------------------------------------------------------- 1 | #Save-Module -Name VstsTaskSdk -Path ..\processtemplate-task\ps_modules\ 2 | 3 | 4 | #Import-Module ..\variabledehydration-task\ps_modules\VstsTaskSdk 5 | 6 | 7 | Invoke-VstsTaskScript -ScriptBlock ([scriptblock]::Create('. ..\variabledehydration-task\dehydrate-veriables.ps1')) -Verbose -------------------------------------------------------------------------------- /variabledehydration-task/v0/dehydrate-variables.ps1: -------------------------------------------------------------------------------- 1 | [CmdletBinding()] 2 | param( 3 | [string] $prefixes, 4 | [string] $outpath 5 | ) 6 | $prefixes = Get-VstsInput -Name prefixes -Require 7 | $outpath = Get-VstsInput -Name outpath -Require 8 | 9 | Write-VstsTaskVerbose "prefixes: $prefixes" 10 | Write-VstsTaskVerbose "outpath: $outpath" 11 | 12 | $prefixesList = $prefixes -split "," 13 | 14 | 15 | foreach ($prefix in $prefixesList) 16 | { 17 | Write-Output "Saving meta data for $prefix" 18 | $path = join-path -path $outpath "meta-$($prefix.ToLower()).json" 19 | Write-VstsTaskVerbose "Save Path: $path" 20 | $PrefixSearch = "Env:$prefix*" 21 | Write-VstsTaskVerbose "Search Prefix: $PrefixSearch" 22 | $variables = Get-Childitem -Path $PrefixSearch | select Name,Value 23 | 24 | Try 25 | { 26 | if ($variables.Length -ne 0) 27 | { 28 | Write-Output $variables 29 | New-Item -ItemType Directory -Force -Path $outpath 30 | $result = $variables | ConvertTo-Json | Out-File $path 31 | Write-Output "created $result" 32 | } 33 | else 34 | { 35 | Write-Output "No variable names matched the prefix $prefix" 36 | } 37 | } 38 | Catch 39 | { 40 | $ErrorMessage = $_.Exception.Message 41 | $FailedItem = $_.Exception.ItemName 42 | Write-VstsTaskError "Did not get a result retunred from the upload, twas not even JSON!" 43 | Write-VstsTaskError $ErrorMessage 44 | Write-VstsTaskError $result 45 | exit 666 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /variabledehydration-task/v0/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkdAgility/azure-devops-variable-tools/cc71f5f1648177772a8bb80473407752c50c0858/variabledehydration-task/v0/icon.png -------------------------------------------------------------------------------- /variabledehydration-task/v0/ps_modules/VstsTaskSdk/FindFunctions.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Finds files or directories. 4 | 5 | .DESCRIPTION 6 | Finds files or directories using advanced pattern matching. 7 | 8 | .PARAMETER LiteralDirectory 9 | Directory to search. 10 | 11 | .PARAMETER LegacyPattern 12 | Proprietary pattern format. The LiteralDirectory parameter is used to root any unrooted patterns. 13 | 14 | Separate multiple patterns using ";". Escape actual ";" in the path by using ";;". 15 | "?" indicates a wildcard that represents any single character within a path segment. 16 | "*" indicates a wildcard that represents zero or more characters within a path segment. 17 | "**" as the entire path segment indicates a recursive search. 18 | "**" within a path segment indicates a recursive intersegment wildcard. 19 | "+:" (can be omitted) indicates an include pattern. 20 | "-:" indicates an exclude pattern. 21 | 22 | The result is from the command is a union of all the matches from the include patterns, minus the matches from the exclude patterns. 23 | 24 | .PARAMETER IncludeFiles 25 | Indicates whether to include files in the results. 26 | 27 | If neither IncludeFiles or IncludeDirectories is set, then IncludeFiles is assumed. 28 | 29 | .PARAMETER IncludeDirectories 30 | Indicates whether to include directories in the results. 31 | 32 | If neither IncludeFiles or IncludeDirectories is set, then IncludeFiles is assumed. 33 | 34 | .PARAMETER Force 35 | Indicates whether to include hidden items. 36 | 37 | .EXAMPLE 38 | Find-VstsFiles -LegacyPattern "C:\Directory\Is?Match.txt" 39 | 40 | Given: 41 | C:\Directory\Is1Match.txt 42 | C:\Directory\Is2Match.txt 43 | C:\Directory\IsNotMatch.txt 44 | 45 | Returns: 46 | C:\Directory\Is1Match.txt 47 | C:\Directory\Is2Match.txt 48 | 49 | .EXAMPLE 50 | Find-VstsFiles -LegacyPattern "C:\Directory\Is*Match.txt" 51 | 52 | Given: 53 | C:\Directory\IsOneMatch.txt 54 | C:\Directory\IsTwoMatch.txt 55 | C:\Directory\NonMatch.txt 56 | 57 | Returns: 58 | C:\Directory\IsOneMatch.txt 59 | C:\Directory\IsTwoMatch.txt 60 | 61 | .EXAMPLE 62 | Find-VstsFiles -LegacyPattern "C:\Directory\**\Match.txt" 63 | 64 | Given: 65 | C:\Directory\Match.txt 66 | C:\Directory\NotAMatch.txt 67 | C:\Directory\SubDir\Match.txt 68 | C:\Directory\SubDir\SubSubDir\Match.txt 69 | 70 | Returns: 71 | C:\Directory\Match.txt 72 | C:\Directory\SubDir\Match.txt 73 | C:\Directory\SubDir\SubSubDir\Match.txt 74 | 75 | .EXAMPLE 76 | Find-VstsFiles -LegacyPattern "C:\Directory\**" 77 | 78 | Given: 79 | C:\Directory\One.txt 80 | C:\Directory\SubDir\Two.txt 81 | C:\Directory\SubDir\SubSubDir\Three.txt 82 | 83 | Returns: 84 | C:\Directory\One.txt 85 | C:\Directory\SubDir\Two.txt 86 | C:\Directory\SubDir\SubSubDir\Three.txt 87 | 88 | .EXAMPLE 89 | Find-VstsFiles -LegacyPattern "C:\Directory\Sub**Match.txt" 90 | 91 | Given: 92 | C:\Directory\IsNotAMatch.txt 93 | C:\Directory\SubDir\IsAMatch.txt 94 | C:\Directory\SubDir\IsNot.txt 95 | C:\Directory\SubDir\SubSubDir\IsAMatch.txt 96 | C:\Directory\SubDir\SubSubDir\IsNot.txt 97 | 98 | Returns: 99 | C:\Directory\SubDir\IsAMatch.txt 100 | C:\Directory\SubDir\SubSubDir\IsAMatch.txt 101 | #> 102 | function Find-Files { 103 | [CmdletBinding()] 104 | param( 105 | [ValidateNotNullOrEmpty()] 106 | [Parameter()] 107 | [string]$LiteralDirectory, 108 | [Parameter(Mandatory = $true)] 109 | [string]$LegacyPattern, 110 | [switch]$IncludeFiles, 111 | [switch]$IncludeDirectories, 112 | [switch]$Force) 113 | 114 | Trace-EnteringInvocation $MyInvocation 115 | if (!$IncludeFiles -and !$IncludeDirectories) { 116 | $IncludeFiles = $true 117 | } 118 | 119 | $includePatterns = New-Object System.Collections.Generic.List[string] 120 | $excludePatterns = New-Object System.Collections.Generic.List[System.Text.RegularExpressions.Regex] 121 | $LegacyPattern = $LegacyPattern.Replace(';;', "`0") 122 | foreach ($pattern in $LegacyPattern.Split(';', [System.StringSplitOptions]::RemoveEmptyEntries)) { 123 | $pattern = $pattern.Replace("`0", ';') 124 | $isIncludePattern = Test-IsIncludePattern -Pattern ([ref]$pattern) 125 | if ($LiteralDirectory -and !([System.IO.Path]::IsPathRooted($pattern))) { 126 | # Use the root directory provided to make the pattern a rooted path. 127 | $pattern = [System.IO.Path]::Combine($LiteralDirectory, $pattern) 128 | } 129 | 130 | # Validate pattern does not end with a \. 131 | if ($pattern[$pattern.Length - 1] -eq [System.IO.Path]::DirectorySeparatorChar) { 132 | throw (Get-LocString -Key PSLIB_InvalidPattern0 -ArgumentList $pattern) 133 | } 134 | 135 | if ($isIncludePattern) { 136 | $includePatterns.Add($pattern) 137 | } else { 138 | $excludePatterns.Add((Convert-PatternToRegex -Pattern $pattern)) 139 | } 140 | } 141 | 142 | $count = 0 143 | foreach ($path in (Get-MatchingItems -IncludePatterns $includePatterns -ExcludePatterns $excludePatterns -IncludeFiles:$IncludeFiles -IncludeDirectories:$IncludeDirectories -Force:$Force)) { 144 | $count++ 145 | $path 146 | } 147 | 148 | Write-Verbose "Total found: $count" 149 | Trace-LeavingInvocation $MyInvocation 150 | } 151 | 152 | ######################################## 153 | # Private functions. 154 | ######################################## 155 | function Convert-PatternToRegex { 156 | [CmdletBinding()] 157 | param([string]$Pattern) 158 | 159 | $Pattern = [regex]::Escape($Pattern.Replace('\', '/')). # Normalize separators and regex escape. 160 | Replace('/\*\*/', '((/.+/)|(/))'). # Replace directory globstar. 161 | Replace('\*\*', '.*'). # Replace remaining globstars with a wildcard that can span directory separators. 162 | Replace('\*', '[^/]*'). # Replace asterisks with a wildcard that cannot span directory separators. 163 | Replace('\?', '.') # Replace single character wildcards. 164 | New-Object regex -ArgumentList "^$Pattern`$", ([System.Text.RegularExpressions.RegexOptions]::IgnoreCase) 165 | } 166 | 167 | function Get-FileNameFilter { 168 | [CmdletBinding()] 169 | param([string]$Pattern) 170 | 171 | $index = $Pattern.LastIndexOf('\') 172 | if ($index -eq -1 -or # Pattern does not contain a backslash. 173 | !($Pattern = $Pattern.Substring($index + 1)) -or # Pattern ends in a backslash. 174 | $Pattern.Contains('**')) # Last segment contains an inter-segment wildcard. 175 | { 176 | return '*' 177 | } 178 | 179 | return $Pattern 180 | } 181 | 182 | function Get-MatchingItems { 183 | [CmdletBinding()] 184 | param( 185 | [System.Collections.Generic.List[string]]$IncludePatterns, 186 | [System.Collections.Generic.List[regex]]$ExcludePatterns, 187 | [switch]$IncludeFiles, 188 | [switch]$IncludeDirectories, 189 | [switch]$Force) 190 | 191 | Trace-EnteringInvocation $MyInvocation 192 | $allFiles = New-Object System.Collections.Generic.HashSet[string] 193 | foreach ($pattern in $IncludePatterns) { 194 | $pathPrefix = Get-PathPrefix -Pattern $pattern 195 | $fileNameFilter = Get-FileNameFilter -Pattern $pattern 196 | $patternRegex = Convert-PatternToRegex -Pattern $pattern 197 | # Iterate over the directories and files under the pathPrefix. 198 | Get-PathIterator -Path $pathPrefix -Filter $fileNameFilter -IncludeFiles:$IncludeFiles -IncludeDirectories:$IncludeDirectories -Force:$Force | 199 | ForEach-Object { 200 | # Normalize separators. 201 | $normalizedPath = $_.Replace('\', '/') 202 | # **/times/** will not match C:/fun/times because there isn't a trailing slash. 203 | # So try both if including directories. 204 | $alternatePath = "$normalizedPath/" 205 | 206 | $isMatch = $false 207 | if ($patternRegex.IsMatch($normalizedPath) -or ($IncludeDirectories -and $patternRegex.IsMatch($alternatePath))) { 208 | $isMatch = $true 209 | 210 | # Test whether the path should be excluded. 211 | foreach ($regex in $ExcludePatterns) { 212 | if ($regex.IsMatch($normalizedPath) -or ($IncludeDirectories -and $regex.IsMatch($alternatePath))) { 213 | $isMatch = $false 214 | break 215 | } 216 | } 217 | } 218 | 219 | if ($isMatch) { 220 | $null = $allFiles.Add($_) 221 | } 222 | } 223 | } 224 | 225 | Trace-Path -Path $allFiles -PassThru 226 | Trace-LeavingInvocation $MyInvocation 227 | } 228 | 229 | function Get-PathIterator { 230 | [CmdletBinding()] 231 | param( 232 | [string]$Path, 233 | [string]$Filter, 234 | [switch]$IncludeFiles, 235 | [switch]$IncludeDirectories, 236 | [switch]$Force) 237 | 238 | if (!$Path) { 239 | return 240 | } 241 | 242 | if ($IncludeDirectories) { 243 | $Path 244 | } 245 | 246 | Get-DirectoryChildItem -Path $Path -Filter $Filter -Force:$Force -Recurse | 247 | ForEach-Object { 248 | if ($_.Attributes.HasFlag([VstsTaskSdk.FS.Attributes]::Directory)) { 249 | if ($IncludeDirectories) { 250 | $_.FullName 251 | } 252 | } elseif ($IncludeFiles) { 253 | $_.FullName 254 | } 255 | } 256 | } 257 | 258 | function Get-PathPrefix { 259 | [CmdletBinding()] 260 | param([string]$Pattern) 261 | 262 | $index = $Pattern.IndexOfAny([char[]]@('*'[0], '?'[0])) 263 | if ($index -eq -1) { 264 | # If no wildcards are found, return the directory name portion of the path. 265 | # If there is no directory name (file name only in pattern), this will return empty string. 266 | return [System.IO.Path]::GetDirectoryName($Pattern) 267 | } 268 | 269 | [System.IO.Path]::GetDirectoryName($Pattern.Substring(0, $index)) 270 | } 271 | 272 | function Test-IsIncludePattern { 273 | [CmdletBinding()] 274 | param( 275 | [Parameter(Mandatory = $true)] 276 | [ref]$Pattern) 277 | 278 | # Include patterns start with +: or anything except -: 279 | # Exclude patterns start with -: 280 | if ($Pattern.value.StartsWith("+:")) { 281 | # Remove the prefix. 282 | $Pattern.value = $Pattern.value.Substring(2) 283 | $true 284 | } elseif ($Pattern.value.StartsWith("-:")) { 285 | # Remove the prefix. 286 | $Pattern.value = $Pattern.value.Substring(2) 287 | $false 288 | } else { 289 | # No prefix, so leave the string alone. 290 | $true; 291 | } 292 | } 293 | -------------------------------------------------------------------------------- /variabledehydration-task/v0/ps_modules/VstsTaskSdk/InputFunctions.ps1: -------------------------------------------------------------------------------- 1 | # Hash table of known variable info. The formatted env var name is the lookup key. 2 | # 3 | # The purpose of this hash table is to keep track of known variables. The hash table 4 | # needs to be maintained for multiple reasons: 5 | # 1) to distinguish between env vars and job vars 6 | # 2) to distinguish between secret vars and public 7 | # 3) to know the real variable name and not just the formatted env var name. 8 | $script:knownVariables = @{ } 9 | $script:vault = @{ } 10 | 11 | <# 12 | .SYNOPSIS 13 | Gets an endpoint. 14 | 15 | .DESCRIPTION 16 | Gets an endpoint object for the specified endpoint name. The endpoint is returned as an object with three properties: Auth, Data, and Url. 17 | 18 | The Data property requires a 1.97 agent or higher. 19 | 20 | .PARAMETER Require 21 | Writes an error to the error pipeline if the endpoint is not found. 22 | #> 23 | function Get-Endpoint { 24 | [CmdletBinding()] 25 | param( 26 | [Parameter(Mandatory = $true)] 27 | [string]$Name, 28 | [switch]$Require) 29 | 30 | $originalErrorActionPreference = $ErrorActionPreference 31 | try { 32 | $ErrorActionPreference = 'Stop' 33 | 34 | # Get the URL. 35 | $description = Get-LocString -Key PSLIB_EndpointUrl0 -ArgumentList $Name 36 | $key = "ENDPOINT_URL_$Name" 37 | $url = Get-VaultValue -Description $description -Key $key -Require:$Require 38 | 39 | # Get the auth object. 40 | $description = Get-LocString -Key PSLIB_EndpointAuth0 -ArgumentList $Name 41 | $key = "ENDPOINT_AUTH_$Name" 42 | if ($auth = (Get-VaultValue -Description $description -Key $key -Require:$Require)) { 43 | $auth = ConvertFrom-Json -InputObject $auth 44 | } 45 | 46 | # Get the data. 47 | $description = "'$Name' service endpoint data" 48 | $key = "ENDPOINT_DATA_$Name" 49 | if ($data = (Get-VaultValue -Description $description -Key $key)) { 50 | $data = ConvertFrom-Json -InputObject $data 51 | } 52 | 53 | # Return the endpoint. 54 | if ($url -or $auth -or $data) { 55 | New-Object -TypeName psobject -Property @{ 56 | Url = $url 57 | Auth = $auth 58 | Data = $data 59 | } 60 | } 61 | } catch { 62 | $ErrorActionPreference = $originalErrorActionPreference 63 | Write-Error $_ 64 | } 65 | } 66 | 67 | <# 68 | .SYNOPSIS 69 | Gets an input. 70 | 71 | .DESCRIPTION 72 | Gets the value for the specified input name. 73 | 74 | .PARAMETER AsBool 75 | Returns the value as a bool. Returns true if the value converted to a string is "1" or "true" (case insensitive); otherwise false. 76 | 77 | .PARAMETER AsInt 78 | Returns the value as an int. Returns the value converted to an int. Returns 0 if the conversion fails. 79 | 80 | .PARAMETER Default 81 | Default value to use if the input is null or empty. 82 | 83 | .PARAMETER Require 84 | Writes an error to the error pipeline if the input is null or empty. 85 | #> 86 | function Get-Input { 87 | [CmdletBinding(DefaultParameterSetName = 'Require')] 88 | param( 89 | [Parameter(Mandatory = $true)] 90 | [string]$Name, 91 | [Parameter(ParameterSetName = 'Default')] 92 | $Default, 93 | [Parameter(ParameterSetName = 'Require')] 94 | [switch]$Require, 95 | [switch]$AsBool, 96 | [switch]$AsInt) 97 | 98 | # Get the input from the vault. Splat the bound parameters hashtable. Splatting is required 99 | # in order to concisely invoke the correct parameter set. 100 | $null = $PSBoundParameters.Remove('Name') 101 | $description = Get-LocString -Key PSLIB_Input0 -ArgumentList $Name 102 | $key = "INPUT_$($Name.Replace(' ', '_').ToUpperInvariant())" 103 | Get-VaultValue @PSBoundParameters -Description $description -Key $key 104 | } 105 | 106 | <# 107 | .SYNOPSIS 108 | Gets a task variable. 109 | 110 | .DESCRIPTION 111 | Gets the value for the specified task variable. 112 | 113 | .PARAMETER AsBool 114 | Returns the value as a bool. Returns true if the value converted to a string is "1" or "true" (case insensitive); otherwise false. 115 | 116 | .PARAMETER AsInt 117 | Returns the value as an int. Returns the value converted to an int. Returns 0 if the conversion fails. 118 | 119 | .PARAMETER Default 120 | Default value to use if the input is null or empty. 121 | 122 | .PARAMETER Require 123 | Writes an error to the error pipeline if the input is null or empty. 124 | #> 125 | function Get-TaskVariable { 126 | [CmdletBinding(DefaultParameterSetName = 'Require')] 127 | param( 128 | [Parameter(Mandatory = $true)] 129 | [string]$Name, 130 | [Parameter(ParameterSetName = 'Default')] 131 | $Default, 132 | [Parameter(ParameterSetName = 'Require')] 133 | [switch]$Require, 134 | [switch]$AsBool, 135 | [switch]$AsInt) 136 | 137 | $originalErrorActionPreference = $ErrorActionPreference 138 | try { 139 | $ErrorActionPreference = 'Stop' 140 | $description = Get-LocString -Key PSLIB_TaskVariable0 -ArgumentList $Name 141 | $variableKey = Get-VariableKey -Name $Name 142 | if ($script:knownVariables.$variableKey.Secret) { 143 | # Get secret variable. Splatting is required to concisely invoke the correct parameter set. 144 | $null = $PSBoundParameters.Remove('Name') 145 | $vaultKey = "SECRET_$variableKey" 146 | Get-VaultValue @PSBoundParameters -Description $description -Key $vaultKey 147 | } else { 148 | # Get public variable. 149 | $item = $null 150 | $path = "Env:$variableKey" 151 | if ((Test-Path -LiteralPath $path) -and ($item = Get-Item -LiteralPath $path).Value) { 152 | # Intentionally empty. Value was successfully retrieved. 153 | } elseif (!$script:nonInteractive) { 154 | # The value wasn't found and the module is running in interactive dev mode. 155 | # Prompt for the value. 156 | Set-Item -LiteralPath $path -Value (Read-Host -Prompt $description) 157 | if (Test-Path -LiteralPath $path) { 158 | $item = Get-Item -LiteralPath $path 159 | } 160 | } 161 | 162 | # Get the converted value. Splatting is required to concisely invoke the correct parameter set. 163 | $null = $PSBoundParameters.Remove('Name') 164 | Get-Value @PSBoundParameters -Description $description -Key $variableKey -Value $item.Value 165 | } 166 | } catch { 167 | $ErrorActionPreference = $originalErrorActionPreference 168 | Write-Error $_ 169 | } 170 | } 171 | 172 | <# 173 | .SYNOPSIS 174 | Gets all job variables available to the task. Requires 2.104.1 agent or higher. 175 | 176 | .DESCRIPTION 177 | Gets a snapshot of the current state of all job variables available to the task. 178 | Requires a 2.104.1 agent or higher for full functionality. 179 | 180 | Returns an array of objects with the following properties: 181 | [string]Name 182 | [string]Value 183 | [bool]Secret 184 | 185 | Limitations on an agent prior to 2.104.1: 186 | 1) The return value does not include all public variables. Only public variables 187 | that have been added using setVariable are returned. 188 | 2) The name returned for each secret variable is the formatted environment variable 189 | name, not the actual variable name (unless it was set explicitly at runtime using 190 | setVariable). 191 | #> 192 | function Get-TaskVariableInfo { 193 | [CmdletBinding()] 194 | param() 195 | 196 | foreach ($info in $script:knownVariables.Values) { 197 | New-Object -TypeName psobject -Property @{ 198 | Name = $info.Name 199 | Value = Get-TaskVariable -Name $info.Name 200 | Secret = $info.Secret 201 | } 202 | } 203 | } 204 | 205 | <# 206 | .SYNOPSIS 207 | Sets a task variable. 208 | 209 | .DESCRIPTION 210 | Sets a task variable in the current task context as well as in the current job context. This allows the task variable to retrieved by subsequent tasks within the same job. 211 | #> 212 | function Set-TaskVariable { 213 | [CmdletBinding()] 214 | param( 215 | [Parameter(Mandatory = $true)] 216 | [string]$Name, 217 | [string]$Value, 218 | [switch]$Secret) 219 | 220 | # Once a secret always a secret. 221 | $variableKey = Get-VariableKey -Name $Name 222 | [bool]$Secret = $Secret -or $script:knownVariables.$variableKey.Secret 223 | if ($Secret) { 224 | $vaultKey = "SECRET_$variableKey" 225 | if (!$Value) { 226 | # Clear the secret. 227 | Write-Verbose "Set $Name = ''" 228 | $script:vault.Remove($vaultKey) 229 | } else { 230 | # Store the secret in the vault. 231 | Write-Verbose "Set $Name = '********'" 232 | $script:vault[$vaultKey] = New-Object System.Management.Automation.PSCredential( 233 | $vaultKey, 234 | (ConvertTo-SecureString -String $Value -AsPlainText -Force)) 235 | } 236 | 237 | # Clear the environment variable. 238 | Set-Item -LiteralPath "Env:$variableKey" -Value '' 239 | } else { 240 | # Set the environment variable. 241 | Write-Verbose "Set $Name = '$Value'" 242 | Set-Item -LiteralPath "Env:$variableKey" -Value $Value 243 | } 244 | 245 | # Store the metadata. 246 | $script:knownVariables[$variableKey] = New-Object -TypeName psobject -Property @{ 247 | Name = $name 248 | Secret = $Secret 249 | } 250 | 251 | # Persist the variable in the task context. 252 | Write-SetVariable -Name $Name -Value $Value -Secret:$Secret 253 | } 254 | 255 | ######################################## 256 | # Private functions. 257 | ######################################## 258 | function Get-VaultValue { 259 | [CmdletBinding(DefaultParameterSetName = 'Require')] 260 | param( 261 | [Parameter(Mandatory = $true)] 262 | [string]$Description, 263 | [Parameter(Mandatory = $true)] 264 | [string]$Key, 265 | [Parameter(ParameterSetName = 'Require')] 266 | [switch]$Require, 267 | [Parameter(ParameterSetName = 'Default')] 268 | [object]$Default, 269 | [switch]$AsBool, 270 | [switch]$AsInt) 271 | 272 | # Attempt to get the vault value. 273 | $value = $null 274 | if ($psCredential = $script:vault[$Key]) { 275 | $value = $psCredential.GetNetworkCredential().Password 276 | } elseif (!$script:nonInteractive) { 277 | # The value wasn't found. Prompt for the value if running in interactive dev mode. 278 | $value = Read-Host -Prompt $Description 279 | if ($value) { 280 | $script:vault[$Key] = New-Object System.Management.Automation.PSCredential( 281 | $Key, 282 | (ConvertTo-SecureString -String $value -AsPlainText -Force)) 283 | } 284 | } 285 | 286 | Get-Value -Value $value @PSBoundParameters 287 | } 288 | 289 | function Get-Value { 290 | [CmdletBinding(DefaultParameterSetName = 'Require')] 291 | param( 292 | [string]$Value, 293 | [Parameter(Mandatory = $true)] 294 | [string]$Description, 295 | [Parameter(Mandatory = $true)] 296 | [string]$Key, 297 | [Parameter(ParameterSetName = 'Require')] 298 | [switch]$Require, 299 | [Parameter(ParameterSetName = 'Default')] 300 | [object]$Default, 301 | [switch]$AsBool, 302 | [switch]$AsInt) 303 | 304 | $result = $Value 305 | if ($result) { 306 | if ($Key -like 'ENDPOINT_AUTH_*') { 307 | Write-Verbose "$($Key): '********'" 308 | } else { 309 | Write-Verbose "$($Key): '$result'" 310 | } 311 | } else { 312 | Write-Verbose "$Key (empty)" 313 | 314 | # Write error if required. 315 | if ($Require) { 316 | Write-Error "$(Get-LocString -Key PSLIB_Required0 $Description)" 317 | return 318 | } 319 | 320 | # Fallback to the default if provided. 321 | if ($PSCmdlet.ParameterSetName -eq 'Default') { 322 | $result = $Default 323 | $OFS = ' ' 324 | Write-Verbose " Defaulted to: '$result'" 325 | } else { 326 | $result = '' 327 | } 328 | } 329 | 330 | # Convert to bool if specified. 331 | if ($AsBool) { 332 | if ($result -isnot [bool]) { 333 | $result = "$result" -in '1', 'true' 334 | Write-Verbose " Converted to bool: $result" 335 | } 336 | 337 | return $result 338 | } 339 | 340 | # Convert to int if specified. 341 | if ($AsInt) { 342 | if ($result -isnot [int]) { 343 | try { 344 | $result = [int]"$result" 345 | } catch { 346 | $result = 0 347 | } 348 | 349 | Write-Verbose " Converted to int: $result" 350 | } 351 | 352 | return $result 353 | } 354 | 355 | return $result 356 | } 357 | 358 | function Initialize-Inputs { 359 | # Store endpoints, inputs, and secret variables in the vault. 360 | foreach ($variable in (Get-ChildItem -Path Env:ENDPOINT_?*, Env:INPUT_?*, Env:SECRET_?*)) { 361 | # Record the secret variable metadata. This is required by Get-TaskVariable to 362 | # retrieve the value. In a 2.104.1 agent or higher, this metadata will be overwritten 363 | # when $env:VSTS_SECRET_VARIABLES is processed. 364 | if ($variable.Name -like 'SECRET_?*') { 365 | $variableKey = $variable.Name.Substring('SECRET_'.Length) 366 | $script:knownVariables[$variableKey] = New-Object -TypeName psobject -Property @{ 367 | # This is technically not the variable name (has underscores instead of dots), 368 | # but it's good enough to make Get-TaskVariable work in a pre-2.104.1 agent 369 | # where $env:VSTS_SECRET_VARIABLES is not defined. 370 | Name = $variableKey 371 | Secret = $true 372 | } 373 | } 374 | 375 | # Store the value in the vault. 376 | $vaultKey = $variable.Name 377 | if ($variable.Value) { 378 | $script:vault[$vaultKey] = New-Object System.Management.Automation.PSCredential( 379 | $vaultKey, 380 | (ConvertTo-SecureString -String $variable.Value -AsPlainText -Force)) 381 | } 382 | 383 | # Clear the environment variable. 384 | Remove-Item -LiteralPath "Env:$($variable.Name)" 385 | } 386 | 387 | # Record the public variable names. Env var added in 2.104.1 agent. 388 | if ($env:VSTS_PUBLIC_VARIABLES) { 389 | foreach ($name in (ConvertFrom-Json -InputObject $env:VSTS_PUBLIC_VARIABLES)) { 390 | $variableKey = Get-VariableKey -Name $name 391 | $script:knownVariables[$variableKey] = New-Object -TypeName psobject -Property @{ 392 | Name = $name 393 | Secret = $false 394 | } 395 | } 396 | 397 | $env:VSTS_PUBLIC_VARIABLES = '' 398 | } 399 | 400 | # Record the secret variable names. Env var added in 2.104.1 agent. 401 | if ($env:VSTS_SECRET_VARIABLES) { 402 | foreach ($name in (ConvertFrom-Json -InputObject $env:VSTS_SECRET_VARIABLES)) { 403 | $variableKey = Get-VariableKey -Name $name 404 | $script:knownVariables[$variableKey] = New-Object -TypeName psobject -Property @{ 405 | Name = $name 406 | Secret = $true 407 | } 408 | } 409 | 410 | $env:VSTS_SECRET_VARIABLES = '' 411 | } 412 | } 413 | 414 | function Get-VariableKey { 415 | [CmdletBinding()] 416 | param( 417 | [Parameter(Mandatory = $true)] 418 | [string]$Name) 419 | 420 | if ($Name -ne 'agent.jobstatus') { 421 | $Name = $Name.Replace('.', '_') 422 | } 423 | 424 | $Name.ToUpperInvariant() 425 | } 426 | -------------------------------------------------------------------------------- /variabledehydration-task/v0/ps_modules/VstsTaskSdk/LocalizationFunctions.ps1: -------------------------------------------------------------------------------- 1 | $script:resourceStrings = @{ } 2 | 3 | <# 4 | .SYNOPSIS 5 | Gets a localized resource string. 6 | 7 | .DESCRIPTION 8 | Gets a localized resource string and optionally formats the string with arguments. 9 | 10 | If the format fails (due to a bad format string or incorrect expected arguments in the format string), then the format string is returned followed by each of the arguments (delimited by a space). 11 | 12 | If the lookup key is not found, then the lookup key is returned followed by each of the arguments (delimited by a space). 13 | 14 | .PARAMETER Require 15 | Writes an error to the error pipeline if the endpoint is not found. 16 | #> 17 | function Get-LocString { 18 | [CmdletBinding()] 19 | param( 20 | [Parameter(Mandatory = $true, Position = 1)] 21 | [string]$Key, 22 | [Parameter(Position = 2)] 23 | [object[]]$ArgumentList = @( )) 24 | 25 | # Due to the dynamically typed nature of PowerShell, a single null argument passed 26 | # to an array parameter is interpreted as a null array. 27 | if ([object]::ReferenceEquals($null, $ArgumentList)) { 28 | $ArgumentList = @( $null ) 29 | } 30 | 31 | # Lookup the format string. 32 | $format = '' 33 | if (!($format = $script:resourceStrings[$Key])) { 34 | # Warn the key was not found. Prevent recursion if the lookup key is the 35 | # "string resource key not found" lookup key. 36 | $resourceNotFoundKey = 'PSLIB_StringResourceKeyNotFound0' 37 | if ($key -ne $resourceNotFoundKey) { 38 | Write-Warning (Get-LocString -Key $resourceNotFoundKey -ArgumentList $Key) 39 | } 40 | 41 | # Fallback to just the key itself if there aren't any arguments to format. 42 | if (!$ArgumentList.Count) { return $key } 43 | 44 | # Otherwise fallback to the key followed by the arguments. 45 | $OFS = " " 46 | return "$key $ArgumentList" 47 | } 48 | 49 | # Return the string if there aren't any arguments to format. 50 | if (!$ArgumentList.Count) { return $format } 51 | 52 | try { 53 | [string]::Format($format, $ArgumentList) 54 | } catch { 55 | Write-Warning (Get-LocString -Key 'PSLIB_StringFormatFailed') 56 | $OFS = " " 57 | "$format $ArgumentList" 58 | } 59 | } 60 | 61 | <# 62 | .SYNOPSIS 63 | Imports resource strings for use with Get-VstsLocString. 64 | 65 | .DESCRIPTION 66 | Imports resource strings for use with Get-VstsLocString. The imported strings are stored in an internal resource string dictionary. Optionally, if a separate resource file for the current culture exists, then the localized strings from that file then imported (overlaid) into the same internal resource string dictionary. 67 | 68 | Resource strings from the SDK are prefixed with "PSLIB_". This prefix should be avoided for custom resource strings. 69 | 70 | .Parameter LiteralPath 71 | JSON file containing resource strings. 72 | 73 | .EXAMPLE 74 | Import-VstsLocStrings -LiteralPath $PSScriptRoot\Task.json 75 | 76 | Imports strings from messages section in the JSON file. If a messages section is not defined, then no strings are imported. Example messages section: 77 | { 78 | "messages": { 79 | "Hello": "Hello you!", 80 | "Hello0": "Hello {0}!" 81 | } 82 | } 83 | 84 | .EXAMPLE 85 | Import-VstsLocStrings -LiteralPath $PSScriptRoot\Task.json 86 | 87 | Overlays strings from an optional separate resource file for the current culture. 88 | 89 | Given the task variable System.Culture is set to 'de-DE'. This variable is set by the agent based on the current culture for the job. 90 | Given the file Task.json contains: 91 | { 92 | "messages": { 93 | "GoodDay": "Good day!", 94 | } 95 | } 96 | Given the file resources.resjson\de-DE\resources.resjson: 97 | { 98 | "loc.messages.GoodDay": "Guten Tag!" 99 | } 100 | 101 | The net result from the import command would be one new key-value pair added to the internal dictionary: Key = 'GoodDay', Value = 'Guten Tag!' 102 | #> 103 | function Import-LocStrings { 104 | [CmdletBinding()] 105 | param( 106 | [Parameter(Mandatory = $true)] 107 | [string]$LiteralPath) 108 | 109 | # Validate the file exists. 110 | if (!(Test-Path -LiteralPath $LiteralPath -PathType Leaf)) { 111 | Write-Warning (Get-LocString -Key PSLIB_FileNotFound0 -ArgumentList $LiteralPath) 112 | return 113 | } 114 | 115 | # Load the json. 116 | Write-Verbose "Loading resource strings from: $LiteralPath" 117 | $count = 0 118 | if ($messages = (Get-Content -LiteralPath $LiteralPath -Encoding UTF8 | Out-String | ConvertFrom-Json).messages) { 119 | # Add each resource string to the hashtable. 120 | foreach ($member in (Get-Member -InputObject $messages -MemberType NoteProperty)) { 121 | [string]$key = $member.Name 122 | $script:resourceStrings[$key] = $messages."$key" 123 | $count++ 124 | } 125 | } 126 | 127 | Write-Verbose "Loaded $count strings." 128 | 129 | # Get the culture. 130 | $culture = Get-TaskVariable -Name "System.Culture" -Default "en-US" 131 | 132 | # Load the resjson. 133 | $resjsonPath = "$([System.IO.Path]::GetDirectoryName($LiteralPath))\Strings\resources.resjson\$culture\resources.resjson" 134 | if (Test-Path -LiteralPath $resjsonPath) { 135 | Write-Verbose "Loading resource strings from: $resjsonPath" 136 | $count = 0 137 | $resjson = Get-Content -LiteralPath $resjsonPath -Encoding UTF8 | Out-String | ConvertFrom-Json 138 | foreach ($member in (Get-Member -Name loc.messages.* -InputObject $resjson -MemberType NoteProperty)) { 139 | if (!($value = $resjson."$($member.Name)")) { 140 | continue 141 | } 142 | 143 | [string]$key = $member.Name.Substring('loc.messages.'.Length) 144 | $script:resourceStrings[$key] = $value 145 | $count++ 146 | } 147 | 148 | Write-Verbose "Loaded $count strings." 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /variabledehydration-task/v0/ps_modules/VstsTaskSdk/LoggingCommandFunctions.ps1: -------------------------------------------------------------------------------- 1 | $script:loggingCommandPrefix = '##vso[' 2 | $script:loggingCommandEscapeMappings = @( # TODO: WHAT ABOUT "="? WHAT ABOUT "%"? 3 | New-Object psobject -Property @{ Token = ';' ; Replacement = '%3B' } 4 | New-Object psobject -Property @{ Token = "`r" ; Replacement = '%0D' } 5 | New-Object psobject -Property @{ Token = "`n" ; Replacement = '%0A' } 6 | ) 7 | # TODO: BUG: Escape ] 8 | # TODO: BUG: Escape % ??? 9 | # TODO: Add test to verify don't need to escape "=". 10 | 11 | <# 12 | .SYNOPSIS 13 | See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md 14 | 15 | .PARAMETER AsOutput 16 | Indicates whether to write the logging command directly to the host or to the output pipeline. 17 | #> 18 | function Write-AddAttachment { 19 | [CmdletBinding()] 20 | param( 21 | [Parameter(Mandatory = $true)] 22 | [string]$Type, 23 | [Parameter(Mandatory = $true)] 24 | [string]$Name, 25 | [Parameter(Mandatory = $true)] 26 | [string]$Path, 27 | [switch]$AsOutput) 28 | 29 | Write-LoggingCommand -Area 'task' -Event 'addattachment' -Data $Path -Properties @{ 30 | 'type' = $Type 31 | 'name' = $Name 32 | } -AsOutput:$AsOutput 33 | } 34 | 35 | <# 36 | .SYNOPSIS 37 | See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md 38 | 39 | .PARAMETER AsOutput 40 | Indicates whether to write the logging command directly to the host or to the output pipeline. 41 | #> 42 | function Write-AddBuildTag { 43 | [CmdletBinding()] 44 | param( 45 | [Parameter(Mandatory = $true)] 46 | [string]$Value, 47 | [switch]$AsOutput) 48 | 49 | Write-LoggingCommand -Area 'build' -Event 'addbuildtag' -Data $Value -AsOutput:$AsOutput 50 | } 51 | 52 | <# 53 | .SYNOPSIS 54 | See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md 55 | 56 | .PARAMETER AsOutput 57 | Indicates whether to write the logging command directly to the host or to the output pipeline. 58 | #> 59 | function Write-AssociateArtifact { 60 | [CmdletBinding()] 61 | param( 62 | [Parameter(Mandatory = $true)] 63 | [string]$Name, 64 | [Parameter(Mandatory = $true)] 65 | [string]$Path, 66 | [Parameter(Mandatory = $true)] 67 | [string]$Type, 68 | [hashtable]$Properties, 69 | [switch]$AsOutput) 70 | 71 | $p = @{ } 72 | if ($Properties) { 73 | foreach ($key in $Properties.Keys) { 74 | $p[$key] = $Properties[$key] 75 | } 76 | } 77 | 78 | $p['artifactname'] = $Name 79 | $p['artifacttype'] = $Type 80 | Write-LoggingCommand -Area 'artifact' -Event 'associate' -Data $Path -Properties $p -AsOutput:$AsOutput 81 | } 82 | 83 | <# 84 | .SYNOPSIS 85 | See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md 86 | 87 | .PARAMETER AsOutput 88 | Indicates whether to write the logging command directly to the host or to the output pipeline. 89 | #> 90 | function Write-LogDetail { 91 | [CmdletBinding()] 92 | param( 93 | [Parameter(Mandatory = $true)] 94 | [guid]$Id, 95 | $ParentId, 96 | [string]$Type, 97 | [string]$Name, 98 | $Order, 99 | $StartTime, 100 | $FinishTime, 101 | $Progress, 102 | [ValidateSet('Unknown', 'Initialized', 'InProgress', 'Completed')] 103 | [Parameter()] 104 | $State, 105 | [ValidateSet('Succeeded', 'SucceededWithIssues', 'Failed', 'Cancelled', 'Skipped')] 106 | [Parameter()] 107 | $Result, 108 | [string]$Message, 109 | [switch]$AsOutput) 110 | 111 | Write-LoggingCommand -Area 'task' -Event 'logdetail' -Data $Message -Properties @{ 112 | 'id' = $Id 113 | 'parentid' = $ParentId 114 | 'type' = $Type 115 | 'name' = $Name 116 | 'order' = $Order 117 | 'starttime' = $StartTime 118 | 'finishtime' = $FinishTime 119 | 'progress' = $Progress 120 | 'state' = $State 121 | 'result' = $Result 122 | } -AsOutput:$AsOutput 123 | } 124 | 125 | <# 126 | .SYNOPSIS 127 | See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md 128 | 129 | .PARAMETER AsOutput 130 | Indicates whether to write the logging command directly to the host or to the output pipeline. 131 | #> 132 | function Write-SetProgress { 133 | [CmdletBinding()] 134 | param( 135 | [ValidateRange(0, 100)] 136 | [Parameter(Mandatory = $true)] 137 | [int]$Percent, 138 | [string]$CurrentOperation, 139 | [switch]$AsOutput) 140 | 141 | Write-LoggingCommand -Area 'task' -Event 'setprogress' -Data $CurrentOperation -Properties @{ 142 | 'value' = $Percent 143 | } -AsOutput:$AsOutput 144 | } 145 | 146 | <# 147 | .SYNOPSIS 148 | See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md 149 | 150 | .PARAMETER AsOutput 151 | Indicates whether to write the logging command directly to the host or to the output pipeline. 152 | #> 153 | function Write-SetResult { 154 | [CmdletBinding(DefaultParameterSetName = 'AsOutput')] 155 | param( 156 | [ValidateSet("Succeeded", "SucceededWithIssues", "Failed", "Cancelled", "Skipped")] 157 | [Parameter(Mandatory = $true)] 158 | [string]$Result, 159 | [string]$Message, 160 | [Parameter(ParameterSetName = 'AsOutput')] 161 | [switch]$AsOutput, 162 | [Parameter(ParameterSetName = 'DoNotThrow')] 163 | [switch]$DoNotThrow) 164 | 165 | Write-LoggingCommand -Area 'task' -Event 'complete' -Data $Message -Properties @{ 166 | 'result' = $Result 167 | } -AsOutput:$AsOutput 168 | if ($Result -eq 'Failed' -and !$AsOutput -and !$DoNotThrow) { 169 | # Special internal exception type to control the flow. Not currently intended 170 | # for public usage and subject to change. 171 | throw (New-Object VstsTaskSdk.TerminationException($Message)) 172 | } 173 | } 174 | 175 | <# 176 | .SYNOPSIS 177 | See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md 178 | 179 | .PARAMETER AsOutput 180 | Indicates whether to write the logging command directly to the host or to the output pipeline. 181 | #> 182 | function Write-SetSecret { 183 | [CmdletBinding()] 184 | param( 185 | [Parameter(Mandatory = $true)] 186 | [string]$Value, 187 | [switch]$AsOutput) 188 | 189 | Write-LoggingCommand -Area 'task' -Event 'setsecret' -Data $Value -AsOutput:$AsOutput 190 | } 191 | 192 | <# 193 | .SYNOPSIS 194 | See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md 195 | 196 | .PARAMETER AsOutput 197 | Indicates whether to write the logging command directly to the host or to the output pipeline. 198 | #> 199 | function Write-SetVariable { 200 | [CmdletBinding()] 201 | param( 202 | [Parameter(Mandatory = $true)] 203 | [string]$Name, 204 | [string]$Value, 205 | [switch]$Secret, 206 | [switch]$AsOutput) 207 | 208 | Write-LoggingCommand -Area 'task' -Event 'setvariable' -Data $Value -Properties @{ 209 | 'variable' = $Name 210 | 'issecret' = $Secret 211 | } -AsOutput:$AsOutput 212 | } 213 | 214 | <# 215 | .SYNOPSIS 216 | See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md 217 | 218 | .PARAMETER AsOutput 219 | Indicates whether to write the logging command directly to the host or to the output pipeline. 220 | #> 221 | function Write-TaskDebug { 222 | [CmdletBinding()] 223 | param( 224 | [string]$Message, 225 | [switch]$AsOutput) 226 | 227 | Write-TaskDebug_Internal @PSBoundParameters 228 | } 229 | 230 | <# 231 | .SYNOPSIS 232 | See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md 233 | 234 | .PARAMETER AsOutput 235 | Indicates whether to write the logging command directly to the host or to the output pipeline. 236 | #> 237 | function Write-TaskError { 238 | [CmdletBinding()] 239 | param( 240 | [string]$Message, 241 | [string]$ErrCode, 242 | [string]$SourcePath, 243 | [string]$LineNumber, 244 | [string]$ColumnNumber, 245 | [switch]$AsOutput) 246 | 247 | Write-LogIssue -Type error @PSBoundParameters 248 | } 249 | 250 | <# 251 | .SYNOPSIS 252 | See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md 253 | 254 | .PARAMETER AsOutput 255 | Indicates whether to write the logging command directly to the host or to the output pipeline. 256 | #> 257 | function Write-TaskVerbose { 258 | [CmdletBinding()] 259 | param( 260 | [string]$Message, 261 | [switch]$AsOutput) 262 | 263 | Write-TaskDebug_Internal @PSBoundParameters -AsVerbose 264 | } 265 | 266 | <# 267 | .SYNOPSIS 268 | See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md 269 | 270 | .PARAMETER AsOutput 271 | Indicates whether to write the logging command directly to the host or to the output pipeline. 272 | #> 273 | function Write-TaskWarning { 274 | [CmdletBinding()] 275 | param( 276 | [string]$Message, 277 | [string]$ErrCode, 278 | [string]$SourcePath, 279 | [string]$LineNumber, 280 | [string]$ColumnNumber, 281 | [switch]$AsOutput) 282 | 283 | Write-LogIssue -Type warning @PSBoundParameters 284 | } 285 | 286 | <# 287 | .SYNOPSIS 288 | See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md 289 | 290 | .PARAMETER AsOutput 291 | Indicates whether to write the logging command directly to the host or to the output pipeline. 292 | #> 293 | function Write-UpdateBuildNumber { 294 | [CmdletBinding()] 295 | param( 296 | [Parameter(Mandatory = $true)] 297 | [string]$Value, 298 | [switch]$AsOutput) 299 | 300 | Write-LoggingCommand -Area 'build' -Event 'updatebuildnumber' -Data $Value -AsOutput:$AsOutput 301 | } 302 | 303 | <# 304 | .SYNOPSIS 305 | See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md 306 | 307 | .PARAMETER AsOutput 308 | Indicates whether to write the logging command directly to the host or to the output pipeline. 309 | #> 310 | function Write-UploadArtifact { 311 | [CmdletBinding()] 312 | param( 313 | [Parameter(Mandatory = $true)] 314 | [string]$ContainerFolder, 315 | [Parameter(Mandatory = $true)] 316 | [string]$Name, 317 | [Parameter(Mandatory = $true)] 318 | [string]$Path, 319 | [switch]$AsOutput) 320 | 321 | Write-LoggingCommand -Area 'artifact' -Event 'upload' -Data $Path -Properties @{ 322 | 'containerfolder' = $ContainerFolder 323 | 'artifactname' = $Name 324 | } -AsOutput:$AsOutput 325 | } 326 | 327 | <# 328 | .SYNOPSIS 329 | See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md 330 | 331 | .PARAMETER AsOutput 332 | Indicates whether to write the logging command directly to the host or to the output pipeline. 333 | #> 334 | function Write-UploadBuildLog { 335 | [CmdletBinding()] 336 | param( 337 | [Parameter(Mandatory = $true)] 338 | [string]$Path, 339 | [switch]$AsOutput) 340 | 341 | Write-LoggingCommand -Area 'build' -Event 'uploadlog' -Data $Path -AsOutput:$AsOutput 342 | } 343 | 344 | ######################################## 345 | # Private functions. 346 | ######################################## 347 | function Format-LoggingCommandData { 348 | [CmdletBinding()] 349 | param([string]$Value, [switch]$Reverse) 350 | 351 | if (!$Value) { 352 | return '' 353 | } 354 | 355 | if (!$Reverse) { 356 | foreach ($mapping in $script:loggingCommandEscapeMappings) { 357 | $Value = $Value.Replace($mapping.Token, $mapping.Replacement) 358 | } 359 | } else { 360 | for ($i = $script:loggingCommandEscapeMappings.Length - 1 ; $i -ge 0 ; $i--) { 361 | $mapping = $script:loggingCommandEscapeMappings[$i] 362 | $Value = $Value.Replace($mapping.Replacement, $mapping.Token) 363 | } 364 | } 365 | 366 | return $Value 367 | } 368 | 369 | function Format-LoggingCommand { 370 | [CmdletBinding()] 371 | param( 372 | [Parameter(Mandatory = $true)] 373 | [string]$Area, 374 | [Parameter(Mandatory = $true)] 375 | [string]$Event, 376 | [string]$Data, 377 | [hashtable]$Properties) 378 | 379 | # Append the preamble. 380 | [System.Text.StringBuilder]$sb = New-Object -TypeName System.Text.StringBuilder 381 | $null = $sb.Append($script:loggingCommandPrefix).Append($Area).Append('.').Append($Event) 382 | 383 | # Append the properties. 384 | if ($Properties) { 385 | $first = $true 386 | foreach ($key in $Properties.Keys) { 387 | [string]$value = Format-LoggingCommandData $Properties[$key] 388 | if ($value) { 389 | if ($first) { 390 | $null = $sb.Append(' ') 391 | $first = $false 392 | } else { 393 | $null = $sb.Append(';') 394 | } 395 | 396 | $null = $sb.Append("$key=$value") 397 | } 398 | } 399 | } 400 | 401 | # Append the tail and output the value. 402 | $Data = Format-LoggingCommandData $Data 403 | $sb.Append(']').Append($Data).ToString() 404 | } 405 | 406 | function Write-LoggingCommand { 407 | [CmdletBinding(DefaultParameterSetName = 'Parameters')] 408 | param( 409 | [Parameter(Mandatory = $true, ParameterSetName = 'Parameters')] 410 | [string]$Area, 411 | [Parameter(Mandatory = $true, ParameterSetName = 'Parameters')] 412 | [string]$Event, 413 | [Parameter(ParameterSetName = 'Parameters')] 414 | [string]$Data, 415 | [Parameter(ParameterSetName = 'Parameters')] 416 | [hashtable]$Properties, 417 | [Parameter(Mandatory = $true, ParameterSetName = 'Object')] 418 | $Command, 419 | [switch]$AsOutput) 420 | 421 | if ($PSCmdlet.ParameterSetName -eq 'Object') { 422 | Write-LoggingCommand -Area $Command.Area -Event $Command.Event -Data $Command.Data -Properties $Command.Properties -AsOutput:$AsOutput 423 | return 424 | } 425 | 426 | $command = Format-LoggingCommand -Area $Area -Event $Event -Data $Data -Properties $Properties 427 | if ($AsOutput) { 428 | $command 429 | } else { 430 | Write-Host $command 431 | } 432 | } 433 | 434 | function Write-LogIssue { 435 | [CmdletBinding()] 436 | param( 437 | [ValidateSet('warning', 'error')] 438 | [Parameter(Mandatory = $true)] 439 | [string]$Type, 440 | [string]$Message, 441 | [string]$ErrCode, 442 | [string]$SourcePath, 443 | [string]$LineNumber, 444 | [string]$ColumnNumber, 445 | [switch]$AsOutput) 446 | 447 | $command = Format-LoggingCommand -Area 'task' -Event 'logissue' -Data $Message -Properties @{ 448 | 'type' = $Type 449 | 'code' = $ErrCode 450 | 'sourcepath' = $SourcePath 451 | 'linenumber' = $LineNumber 452 | 'columnnumber' = $ColumnNumber 453 | } 454 | if ($AsOutput) { 455 | return $command 456 | } 457 | 458 | if ($Type -eq 'error') { 459 | $foregroundColor = $host.PrivateData.ErrorForegroundColor 460 | $backgroundColor = $host.PrivateData.ErrorBackgroundColor 461 | if ($foregroundColor -isnot [System.ConsoleColor] -or $backgroundColor -isnot [System.ConsoleColor]) { 462 | $foregroundColor = [System.ConsoleColor]::Red 463 | $backgroundColor = [System.ConsoleColor]::Black 464 | } 465 | } else { 466 | $foregroundColor = $host.PrivateData.WarningForegroundColor 467 | $backgroundColor = $host.PrivateData.WarningBackgroundColor 468 | if ($foregroundColor -isnot [System.ConsoleColor] -or $backgroundColor -isnot [System.ConsoleColor]) { 469 | $foregroundColor = [System.ConsoleColor]::Yellow 470 | $backgroundColor = [System.ConsoleColor]::Black 471 | } 472 | } 473 | 474 | Write-Host $command -ForegroundColor $foregroundColor -BackgroundColor $backgroundColor 475 | } 476 | 477 | function Write-TaskDebug_Internal { 478 | [CmdletBinding()] 479 | param( 480 | [string]$Message, 481 | [switch]$AsVerbose, 482 | [switch]$AsOutput) 483 | 484 | $command = Format-LoggingCommand -Area 'task' -Event 'debug' -Data $Message 485 | if ($AsOutput) { 486 | return $command 487 | } 488 | 489 | if ($AsVerbose) { 490 | $foregroundColor = $host.PrivateData.VerboseForegroundColor 491 | $backgroundColor = $host.PrivateData.VerboseBackgroundColor 492 | if ($foregroundColor -isnot [System.ConsoleColor] -or $backgroundColor -isnot [System.ConsoleColor]) { 493 | $foregroundColor = [System.ConsoleColor]::Cyan 494 | $backgroundColor = [System.ConsoleColor]::Black 495 | } 496 | } else { 497 | $foregroundColor = $host.PrivateData.DebugForegroundColor 498 | $backgroundColor = $host.PrivateData.DebugBackgroundColor 499 | if ($foregroundColor -isnot [System.ConsoleColor] -or $backgroundColor -isnot [System.ConsoleColor]) { 500 | $foregroundColor = [System.ConsoleColor]::DarkGray 501 | $backgroundColor = [System.ConsoleColor]::Black 502 | } 503 | } 504 | 505 | Write-Host -Object $command -ForegroundColor $foregroundColor -BackgroundColor $backgroundColor 506 | } 507 | -------------------------------------------------------------------------------- /variabledehydration-task/v0/ps_modules/VstsTaskSdk/LongPathFunctions.ps1: -------------------------------------------------------------------------------- 1 | ######################################## 2 | # Private functions. 3 | ######################################## 4 | function ConvertFrom-LongFormPath { 5 | [CmdletBinding()] 6 | param([string]$Path) 7 | 8 | if ($Path) { 9 | if ($Path.StartsWith('\\?\UNC')) { 10 | # E.g. \\?\UNC\server\share -> \\server\share 11 | return $Path.Substring(1, '\?\UNC'.Length) 12 | } elseif ($Path.StartsWith('\\?\')) { 13 | # E.g. \\?\C:\directory -> C:\directory 14 | return $Path.Substring('\\?\'.Length) 15 | } 16 | } 17 | 18 | return $Path 19 | } 20 | function ConvertTo-LongFormPath { 21 | [CmdletBinding()] 22 | param( 23 | [Parameter(Mandatory = $true)] 24 | [string]$Path) 25 | 26 | [string]$longFormPath = Get-FullNormalizedPath -Path $Path 27 | if ($longFormPath -and !$longFormPath.StartsWith('\\?')) { 28 | if ($longFormPath.StartsWith('\\')) { 29 | # E.g. \\server\share -> \\?\UNC\server\share 30 | return "\\?\UNC$($longFormPath.Substring(1))" 31 | } else { 32 | # E.g. C:\directory -> \\?\C:\directory 33 | return "\\?\$longFormPath" 34 | } 35 | } 36 | 37 | return $longFormPath 38 | } 39 | 40 | # TODO: ADD A SWITCH TO EXCLUDE FILES, A SWITCH TO EXCLUDE DIRECTORIES, AND A SWITCH NOT TO FOLLOW REPARSE POINTS. 41 | function Get-DirectoryChildItem { 42 | [CmdletBinding()] 43 | param( 44 | [string]$Path, 45 | [ValidateNotNullOrEmpty()] 46 | [Parameter()] 47 | [string]$Filter = "*", 48 | [switch]$Force, 49 | [VstsTaskSdk.FS.FindFlags]$Flags = [VstsTaskSdk.FS.FindFlags]::LargeFetch, 50 | [VstsTaskSdk.FS.FindInfoLevel]$InfoLevel = [VstsTaskSdk.FS.FindInfoLevel]::Basic, 51 | [switch]$Recurse) 52 | 53 | $stackOfDirectoryQueues = New-Object System.Collections.Stack 54 | while ($true) { 55 | $directoryQueue = New-Object System.Collections.Queue 56 | $fileQueue = New-Object System.Collections.Queue 57 | $findData = New-Object VstsTaskSdk.FS.FindData 58 | $longFormPath = (ConvertTo-LongFormPath $Path) 59 | $handle = $null 60 | try { 61 | $handle = [VstsTaskSdk.FS.NativeMethods]::FindFirstFileEx( 62 | [System.IO.Path]::Combine($longFormPath, $Filter), 63 | $InfoLevel, 64 | $findData, 65 | [VstsTaskSdk.FS.FindSearchOps]::NameMatch, 66 | [System.IntPtr]::Zero, 67 | $Flags) 68 | if (!$handle.IsInvalid) { 69 | while ($true) { 70 | if ($findData.fileName -notin '.', '..') { 71 | $attributes = [VstsTaskSdk.FS.Attributes]$findData.fileAttributes 72 | # If the item is hidden, check if $Force is specified. 73 | if ($Force -or !$attributes.HasFlag([VstsTaskSdk.FS.Attributes]::Hidden)) { 74 | # Create the item. 75 | $item = New-Object -TypeName psobject -Property @{ 76 | 'Attributes' = $attributes 77 | 'FullName' = (ConvertFrom-LongFormPath -Path ([System.IO.Path]::Combine($Path, $findData.fileName))) 78 | 'Name' = $findData.fileName 79 | } 80 | # Output directories immediately. 81 | if ($item.Attributes.HasFlag([VstsTaskSdk.FS.Attributes]::Directory)) { 82 | $item 83 | # Append to the directory queue if recursive and default filter. 84 | if ($Recurse -and $Filter -eq '*') { 85 | $directoryQueue.Enqueue($item) 86 | } 87 | } else { 88 | # Hold the files until all directories have been output. 89 | $fileQueue.Enqueue($item) 90 | } 91 | } 92 | } 93 | 94 | if (!([VstsTaskSdk.FS.NativeMethods]::FindNextFile($handle, $findData))) { break } 95 | 96 | if ($handle.IsInvalid) { 97 | throw (New-Object -TypeName System.ComponentModel.Win32Exception -ArgumentList @( 98 | [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() 99 | Get-LocString -Key PSLIB_EnumeratingSubdirectoriesFailedForPath0 -ArgumentList $Path 100 | )) 101 | } 102 | } 103 | } 104 | } finally { 105 | if ($handle -ne $null) { $handle.Dispose() } 106 | } 107 | 108 | # If recursive and non-default filter, queue child directories. 109 | if ($Recurse -and $Filter -ne '*') { 110 | $findData = New-Object VstsTaskSdk.FS.FindData 111 | $handle = $null 112 | try { 113 | $handle = [VstsTaskSdk.FS.NativeMethods]::FindFirstFileEx( 114 | [System.IO.Path]::Combine($longFormPath, '*'), 115 | [VstsTaskSdk.FS.FindInfoLevel]::Basic, 116 | $findData, 117 | [VstsTaskSdk.FS.FindSearchOps]::NameMatch, 118 | [System.IntPtr]::Zero, 119 | $Flags) 120 | if (!$handle.IsInvalid) { 121 | while ($true) { 122 | if ($findData.fileName -notin '.', '..') { 123 | $attributes = [VstsTaskSdk.FS.Attributes]$findData.fileAttributes 124 | # If the item is hidden, check if $Force is specified. 125 | if ($Force -or !$attributes.HasFlag([VstsTaskSdk.FS.Attributes]::Hidden)) { 126 | # Collect directories only. 127 | if ($attributes.HasFlag([VstsTaskSdk.FS.Attributes]::Directory)) { 128 | # Create the item. 129 | $item = New-Object -TypeName psobject -Property @{ 130 | 'Attributes' = $attributes 131 | 'FullName' = (ConvertFrom-LongFormPath -Path ([System.IO.Path]::Combine($Path, $findData.fileName))) 132 | 'Name' = $findData.fileName 133 | } 134 | $directoryQueue.Enqueue($item) 135 | } 136 | } 137 | } 138 | 139 | if (!([VstsTaskSdk.FS.NativeMethods]::FindNextFile($handle, $findData))) { break } 140 | 141 | if ($handle.IsInvalid) { 142 | throw (New-Object -TypeName System.ComponentModel.Win32Exception -ArgumentList @( 143 | [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() 144 | Get-LocString -Key PSLIB_EnumeratingSubdirectoriesFailedForPath0 -ArgumentList $Path 145 | )) 146 | } 147 | } 148 | } 149 | } finally { 150 | if ($handle -ne $null) { $handle.Dispose() } 151 | } 152 | } 153 | 154 | # Output the files. 155 | $fileQueue 156 | 157 | # Push the directory queue onto the stack if any directories were found. 158 | if ($directoryQueue.Count) { $stackOfDirectoryQueues.Push($directoryQueue) } 159 | 160 | # Break out of the loop if no more directory queues to process. 161 | if (!$stackOfDirectoryQueues.Count) { break } 162 | 163 | # Get the next path. 164 | $directoryQueue = $stackOfDirectoryQueues.Peek() 165 | $Path = $directoryQueue.Dequeue().FullName 166 | 167 | # Pop the directory queue if it's empty. 168 | if (!$directoryQueue.Count) { $null = $stackOfDirectoryQueues.Pop() } 169 | } 170 | } 171 | 172 | function Get-FullNormalizedPath { 173 | [CmdletBinding()] 174 | param( 175 | [Parameter(Mandatory = $true)] 176 | [string]$Path) 177 | 178 | [string]$outPath = $Path 179 | [uint32]$bufferSize = [VstsTaskSdk.FS.NativeMethods]::GetFullPathName($Path, 0, $null, $null) 180 | [int]$lastWin32Error = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() 181 | if ($bufferSize -gt 0) { 182 | $absolutePath = New-Object System.Text.StringBuilder([int]$bufferSize) 183 | [uint32]$length = [VstsTaskSdk.FS.NativeMethods]::GetFullPathName($Path, $bufferSize, $absolutePath, $null) 184 | $lastWin32Error = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() 185 | if ($length -gt 0) { 186 | $outPath = $absolutePath.ToString() 187 | } else { 188 | throw (New-Object -TypeName System.ComponentModel.Win32Exception -ArgumentList @( 189 | $lastWin32Error 190 | Get-LocString -Key PSLIB_PathLengthNotReturnedFor0 -ArgumentList $Path 191 | )) 192 | } 193 | } else { 194 | throw (New-Object -TypeName System.ComponentModel.Win32Exception -ArgumentList @( 195 | $lastWin32Error 196 | Get-LocString -Key PSLIB_PathLengthNotReturnedFor0 -ArgumentList $Path 197 | )) 198 | } 199 | 200 | if ($outPath.EndsWith('\') -and !$outPath.EndsWith(':\')) { 201 | $outPath = $outPath.TrimEnd('\') 202 | } 203 | 204 | $outPath 205 | } 206 | 207 | ######################################## 208 | # Types. 209 | ######################################## 210 | # If the type has already been loaded once, then it is not loaded again. 211 | Write-Verbose "Adding long path native methods." 212 | Add-Type -Debug:$false -TypeDefinition @' 213 | namespace VstsTaskSdk.FS 214 | { 215 | using System; 216 | using System.Runtime.InteropServices; 217 | 218 | public static class NativeMethods 219 | { 220 | private const string Kernel32Dll = "kernel32.dll"; 221 | 222 | [DllImport(Kernel32Dll, CharSet = CharSet.Unicode, BestFitMapping = false, ThrowOnUnmappableChar = true)] 223 | [return: MarshalAs(UnmanagedType.Bool)] 224 | public static extern bool FindClose(IntPtr hFindFile); 225 | 226 | // HANDLE WINAPI FindFirstFile( 227 | // _In_ LPCTSTR lpFileName, 228 | // _Out_ LPWIN32_FIND_DATA lpFindFileData 229 | // ); 230 | [DllImport(Kernel32Dll, CharSet = CharSet.Unicode, BestFitMapping = false, ThrowOnUnmappableChar = true, SetLastError = true)] 231 | public static extern SafeFindHandle FindFirstFile( 232 | [MarshalAs(UnmanagedType.LPTStr)] 233 | string fileName, 234 | [In, Out] FindData findFileData 235 | ); 236 | 237 | //HANDLE WINAPI FindFirstFileEx( 238 | // _In_ LPCTSTR lpFileName, 239 | // _In_ FINDEX_INFO_LEVELS fInfoLevelId, 240 | // _Out_ LPVOID lpFindFileData, 241 | // _In_ FINDEX_SEARCH_OPS fSearchOp, 242 | // _Reserved_ LPVOID lpSearchFilter, 243 | // _In_ DWORD dwAdditionalFlags 244 | //); 245 | [DllImport(Kernel32Dll, CharSet = CharSet.Unicode, BestFitMapping = false, ThrowOnUnmappableChar = true, SetLastError = true)] 246 | public static extern SafeFindHandle FindFirstFileEx( 247 | [MarshalAs(UnmanagedType.LPTStr)] 248 | string fileName, 249 | [In] FindInfoLevel fInfoLevelId, 250 | [In, Out] FindData lpFindFileData, 251 | [In] FindSearchOps fSearchOp, 252 | IntPtr lpSearchFilter, 253 | [In] FindFlags dwAdditionalFlags 254 | ); 255 | 256 | [DllImport(Kernel32Dll, CharSet = CharSet.Unicode, BestFitMapping = false, ThrowOnUnmappableChar = true, SetLastError = true)] 257 | [return: MarshalAs(UnmanagedType.Bool)] 258 | public static extern bool FindNextFile(SafeFindHandle hFindFile, [In, Out] FindData lpFindFileData); 259 | 260 | [DllImport(Kernel32Dll, CharSet = CharSet.Unicode, BestFitMapping = false, ThrowOnUnmappableChar = true, SetLastError = true)] 261 | public static extern int GetFileAttributes(string lpFileName); 262 | 263 | [DllImport(Kernel32Dll, CharSet = CharSet.Unicode, BestFitMapping = false, ThrowOnUnmappableChar = true, SetLastError = true)] 264 | public static extern uint GetFullPathName( 265 | [MarshalAs(UnmanagedType.LPTStr)] 266 | string lpFileName, 267 | uint nBufferLength, 268 | [Out] 269 | System.Text.StringBuilder lpBuffer, 270 | System.Text.StringBuilder lpFilePart 271 | ); 272 | } 273 | 274 | //for mapping to the WIN32_FIND_DATA native structure 275 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 276 | public sealed class FindData 277 | { 278 | // NOTE: 279 | // Although it may seem correct to Marshal the string members of this class as UnmanagedType.LPWStr, they 280 | // must explicitly remain UnmanagedType.ByValTStr with the size constraints noted. Otherwise we end up with 281 | // COM Interop exceptions while trying to marshal the data across the PInvoke boundaries. 282 | public int fileAttributes; 283 | public System.Runtime.InteropServices.ComTypes.FILETIME creationTime; 284 | public System.Runtime.InteropServices.ComTypes.FILETIME lastAccessTime; 285 | public System.Runtime.InteropServices.ComTypes.FILETIME lastWriteTime; 286 | public int nFileSizeHigh; 287 | public int nFileSizeLow; 288 | public int dwReserved0; 289 | public int dwReserved1; 290 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] 291 | public string fileName; 292 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)] 293 | public string alternateFileName; 294 | } 295 | 296 | //A Win32 safe find handle in which a return value of -1 indicates it's invalid 297 | public sealed class SafeFindHandle : Microsoft.Win32.SafeHandles.SafeHandleMinusOneIsInvalid 298 | { 299 | public SafeFindHandle() 300 | : base(true) 301 | { 302 | return; 303 | } 304 | 305 | [System.Runtime.ConstrainedExecution.ReliabilityContract(System.Runtime.ConstrainedExecution.Consistency.WillNotCorruptState, System.Runtime.ConstrainedExecution.Cer.Success)] 306 | protected override bool ReleaseHandle() 307 | { 308 | return NativeMethods.FindClose(handle); 309 | } 310 | } 311 | 312 | // Refer https://msdn.microsoft.com/en-us/library/windows/desktop/gg258117(v=vs.85).aspx 313 | [Flags] 314 | public enum Attributes : uint 315 | { 316 | None = 0x00000000, 317 | Readonly = 0x00000001, 318 | Hidden = 0x00000002, 319 | System = 0x00000004, 320 | Directory = 0x00000010, 321 | Archive = 0x00000020, 322 | Device = 0x00000040, 323 | Normal = 0x00000080, 324 | Temporary = 0x00000100, 325 | SparseFile = 0x00000200, 326 | ReparsePoint = 0x00000400, 327 | Compressed = 0x00000800, 328 | Offline = 0x00001000, 329 | NotContentIndexed = 0x00002000, 330 | Encrypted = 0x00004000, 331 | IntegrityStream = 0x00008000, 332 | Virtual = 0x00010000, 333 | NoScrubData = 0x00020000, 334 | Write_Through = 0x80000000, 335 | Overlapped = 0x40000000, 336 | NoBuffering = 0x20000000, 337 | RandomAccess = 0x10000000, 338 | SequentialScan = 0x08000000, 339 | DeleteOnClose = 0x04000000, 340 | BackupSemantics = 0x02000000, 341 | PosixSemantics = 0x01000000, 342 | OpenReparsePoint = 0x00200000, 343 | OpenNoRecall = 0x00100000, 344 | FirstPipeInstance = 0x00080000 345 | } 346 | 347 | [Flags] 348 | public enum FindFlags 349 | { 350 | None = 0, 351 | CaseSensitive = 1, 352 | LargeFetch = 2, 353 | } 354 | 355 | public enum FindInfoLevel 356 | { 357 | Standard = 0, 358 | Basic = 1, 359 | } 360 | 361 | public enum FindSearchOps 362 | { 363 | NameMatch = 0, 364 | LimitToDirectories = 1, 365 | LimitToDevices = 2, 366 | } 367 | } 368 | '@ 369 | -------------------------------------------------------------------------------- /variabledehydration-task/v0/ps_modules/VstsTaskSdk/OutFunctions.ps1: -------------------------------------------------------------------------------- 1 | # TODO: It would be better if the Out-Default function resolved the underlying Out-Default 2 | # command in the begin block. This would allow for supporting other modules that override 3 | # Out-Default. 4 | $script:outDefaultCmdlet = $ExecutionContext.InvokeCommand.GetCmdlet("Microsoft.PowerShell.Core\Out-Default") 5 | 6 | ######################################## 7 | # Public functions. 8 | ######################################## 9 | function Out-Default { 10 | [CmdletBinding(ConfirmImpact = "Medium")] 11 | param( 12 | [Parameter(ValueFromPipeline = $true)] 13 | [System.Management.Automation.PSObject]$InputObject) 14 | 15 | begin { 16 | #Write-Host '[Entering Begin Out-Default]' 17 | $__sp = { & $script:outDefaultCmdlet @PSBoundParameters }.GetSteppablePipeline() 18 | $__sp.Begin($pscmdlet) 19 | #Write-Host '[Leaving Begin Out-Default]' 20 | } 21 | 22 | process { 23 | #Write-Host '[Entering Process Out-Default]' 24 | if ($_ -is [System.Management.Automation.ErrorRecord]) { 25 | Write-Verbose -Message 'Error record:' 4>&1 | Out-Default 26 | Write-Verbose -Message (Remove-TrailingNewLine (Out-String -InputObject $_ -Width 2147483647)) 4>&1 | Out-Default 27 | Write-Verbose -Message 'Script stack trace:' 4>&1 | Out-Default 28 | Write-Verbose -Message "$($_.ScriptStackTrace)" 4>&1 | Out-Default 29 | Write-Verbose -Message 'Exception:' 4>&1 | Out-Default 30 | Write-Verbose -Message $_.Exception.ToString() 4>&1 | Out-Default 31 | Write-TaskError -Message $_.Exception.Message 32 | } elseif ($_ -is [System.Management.Automation.WarningRecord]) { 33 | Write-TaskWarning -Message (Remove-TrailingNewLine (Out-String -InputObject $_ -Width 2147483647)) 34 | } elseif ($_ -is [System.Management.Automation.VerboseRecord]) { 35 | foreach ($private:str in (Format-DebugMessage -Object $_)) { 36 | Write-TaskVerbose -Message $private:str 37 | } 38 | } elseif ($_ -is [System.Management.Automation.DebugRecord]) { 39 | foreach ($private:str in (Format-DebugMessage -Object $_)) { 40 | Write-TaskDebug -Message $private:str 41 | } 42 | } else { 43 | # TODO: Consider using out-string here to control the width. As a security precaution it would actually be best to set it to max so wrapping doesn't interfere with secret masking. 44 | $__sp.Process($_) 45 | } 46 | 47 | #Write-Host '[Leaving Process Out-Default]' 48 | } 49 | 50 | end { 51 | #Write-Host '[Entering End Out-Default]' 52 | $__sp.End() 53 | #Write-Host '[Leaving End Out-Default]' 54 | } 55 | } 56 | 57 | ######################################## 58 | # Private functions. 59 | ######################################## 60 | function Format-DebugMessage { 61 | [CmdletBinding()] 62 | param([psobject]$Object) 63 | 64 | $private:str = Out-String -InputObject $Object -Width 2147483647 65 | $private:str = Remove-TrailingNewLine $private:str 66 | "$private:str".Replace("`r`n", "`n").Replace("`r", "`n").Split("`n"[0]) 67 | } 68 | 69 | function Remove-TrailingNewLine { 70 | [CmdletBinding()] 71 | param($Str) 72 | if ([object]::ReferenceEquals($Str, $null)) { 73 | return $Str 74 | } elseif ($Str.EndsWith("`r`n")) { 75 | return $Str.Substring(0, $Str.Length - 2) 76 | } else { 77 | return $Str 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /variabledehydration-task/v0/ps_modules/VstsTaskSdk/PSGetModuleInfo.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkdAgility/azure-devops-variable-tools/cc71f5f1648177772a8bb80473407752c50c0858/variabledehydration-task/v0/ps_modules/VstsTaskSdk/PSGetModuleInfo.xml -------------------------------------------------------------------------------- /variabledehydration-task/v0/ps_modules/VstsTaskSdk/Strings/resources.resjson/de-de/resources.resjson: -------------------------------------------------------------------------------- 1 | { 2 | "loc.messages.PSLIB_ContainerPathNotFound0": "Der Containerpfad wurde nicht gefunden: \"{0}\".", 3 | "loc.messages.PSLIB_EndpointAuth0": "\"{0}\"-Dienstendpunkt-Anmeldeinformationen", 4 | "loc.messages.PSLIB_EndpointUrl0": "\"{0}\"-Dienstendpunkt-URL", 5 | "loc.messages.PSLIB_EnumeratingSubdirectoriesFailedForPath0": "Fehler beim Aufzählen von Unterverzeichnissen für den folgenden Pfad: \"{0}\"", 6 | "loc.messages.PSLIB_FileNotFound0": "Die Datei wurde nicht gefunden: \"{0}\".", 7 | "loc.messages.PSLIB_Input0": "\"{0}\"-Eingabe", 8 | "loc.messages.PSLIB_InvalidPattern0": "Ungültiges Muster: \"{0}\"", 9 | "loc.messages.PSLIB_LeafPathNotFound0": "Der Blattpfad wurde nicht gefunden: \"{0}\".", 10 | "loc.messages.PSLIB_PathLengthNotReturnedFor0": "Fehler bei der Normalisierung bzw. Erweiterung des Pfads. Die Pfadlänge wurde vom Kernel32-Subsystem nicht zurückgegeben für: \"{0}\"", 11 | "loc.messages.PSLIB_PathNotFound0": "Der Pfad wurde nicht gefunden: \"{0}\".", 12 | "loc.messages.PSLIB_Process0ExitedWithCode1": "Der Prozess \"{0}\" wurde mit dem Code \"{1}\" beendet.", 13 | "loc.messages.PSLIB_Required0": "Erforderlich: {0}", 14 | "loc.messages.PSLIB_StringFormatFailed": "Fehler beim Zeichenfolgenformat.", 15 | "loc.messages.PSLIB_StringResourceKeyNotFound0": "Der Zeichenfolgen-Ressourcenschlüssel wurde nicht gefunden: \"{0}\".", 16 | "loc.messages.PSLIB_TaskVariable0": "\"{0}\"-Taskvariable" 17 | } -------------------------------------------------------------------------------- /variabledehydration-task/v0/ps_modules/VstsTaskSdk/Strings/resources.resjson/en-US/resources.resjson: -------------------------------------------------------------------------------- 1 | { 2 | "loc.messages.PSLIB_ContainerPathNotFound0": "Container path not found: '{0}'", 3 | "loc.messages.PSLIB_EndpointAuth0": "'{0}' service endpoint credentials", 4 | "loc.messages.PSLIB_EndpointUrl0": "'{0}' service endpoint URL", 5 | "loc.messages.PSLIB_EnumeratingSubdirectoriesFailedForPath0": "Enumerating subdirectories failed for path: '{0}'", 6 | "loc.messages.PSLIB_FileNotFound0": "File not found: '{0}'", 7 | "loc.messages.PSLIB_Input0": "'{0}' input", 8 | "loc.messages.PSLIB_InvalidPattern0": "Invalid pattern: '{0}'", 9 | "loc.messages.PSLIB_LeafPathNotFound0": "Leaf path not found: '{0}'", 10 | "loc.messages.PSLIB_PathLengthNotReturnedFor0": "Path normalization/expansion failed. The path length was not returned by the Kernel32 subsystem for: '{0}'", 11 | "loc.messages.PSLIB_PathNotFound0": "Path not found: '{0}'", 12 | "loc.messages.PSLIB_Process0ExitedWithCode1": "Process '{0}' exited with code '{1}'.", 13 | "loc.messages.PSLIB_Required0": "Required: {0}", 14 | "loc.messages.PSLIB_StringFormatFailed": "String format failed.", 15 | "loc.messages.PSLIB_StringResourceKeyNotFound0": "String resource key not found: '{0}'", 16 | "loc.messages.PSLIB_TaskVariable0": "'{0}' task variable" 17 | } -------------------------------------------------------------------------------- /variabledehydration-task/v0/ps_modules/VstsTaskSdk/Strings/resources.resjson/es-es/resources.resjson: -------------------------------------------------------------------------------- 1 | { 2 | "loc.messages.PSLIB_ContainerPathNotFound0": "No se encuentra la ruta de acceso del contenedor: '{0}'", 3 | "loc.messages.PSLIB_EndpointAuth0": "Credenciales del punto de conexión de servicio '{0}'", 4 | "loc.messages.PSLIB_EndpointUrl0": "URL del punto de conexión de servicio '{0}'", 5 | "loc.messages.PSLIB_EnumeratingSubdirectoriesFailedForPath0": "No se pudieron enumerar los subdirectorios de la ruta de acceso: '{0}'", 6 | "loc.messages.PSLIB_FileNotFound0": "Archivo no encontrado: '{0}'", 7 | "loc.messages.PSLIB_Input0": "Entrada '{0}'", 8 | "loc.messages.PSLIB_InvalidPattern0": "Patrón no válido: '{0}'", 9 | "loc.messages.PSLIB_LeafPathNotFound0": "No se encuentra la ruta de acceso de la hoja: '{0}'", 10 | "loc.messages.PSLIB_PathLengthNotReturnedFor0": "No se pudo normalizar o expandir la ruta de acceso. El subsistema Kernel32 no devolvió la longitud de la ruta de acceso para: '{0}'", 11 | "loc.messages.PSLIB_PathNotFound0": "No se encuentra la ruta de acceso: '{0}'", 12 | "loc.messages.PSLIB_Process0ExitedWithCode1": "El proceso '{0}' finalizó con el código '{1}'.", 13 | "loc.messages.PSLIB_Required0": "Se requiere: {0}", 14 | "loc.messages.PSLIB_StringFormatFailed": "Error de formato de cadena.", 15 | "loc.messages.PSLIB_StringResourceKeyNotFound0": "No se encuentra la clave de recurso de la cadena: '{0}'", 16 | "loc.messages.PSLIB_TaskVariable0": "Variable de tarea '{0}'" 17 | } -------------------------------------------------------------------------------- /variabledehydration-task/v0/ps_modules/VstsTaskSdk/Strings/resources.resjson/fr-fr/resources.resjson: -------------------------------------------------------------------------------- 1 | { 2 | "loc.messages.PSLIB_ContainerPathNotFound0": "Le chemin du conteneur est introuvable : '{0}'", 3 | "loc.messages.PSLIB_EndpointAuth0": "Informations d'identification du point de terminaison de service '{0}'", 4 | "loc.messages.PSLIB_EndpointUrl0": "URL du point de terminaison de service '{0}'", 5 | "loc.messages.PSLIB_EnumeratingSubdirectoriesFailedForPath0": "Échec de l'énumération des sous-répertoires pour le chemin : '{0}'", 6 | "loc.messages.PSLIB_FileNotFound0": "Fichier introuvable : {0}.", 7 | "loc.messages.PSLIB_Input0": "Entrée '{0}'", 8 | "loc.messages.PSLIB_InvalidPattern0": "Modèle non valide : '{0}'", 9 | "loc.messages.PSLIB_LeafPathNotFound0": "Le chemin feuille est introuvable : '{0}'", 10 | "loc.messages.PSLIB_PathLengthNotReturnedFor0": "Échec de la normalisation/l'expansion du chemin. La longueur du chemin n'a pas été retournée par le sous-système Kernel32 pour : '{0}'", 11 | "loc.messages.PSLIB_PathNotFound0": "Chemin introuvable : '{0}'", 12 | "loc.messages.PSLIB_Process0ExitedWithCode1": "Le processus '{0}' s'est arrêté avec le code '{1}'.", 13 | "loc.messages.PSLIB_Required0": "Obligatoire : {0}", 14 | "loc.messages.PSLIB_StringFormatFailed": "Échec du format de la chaîne.", 15 | "loc.messages.PSLIB_StringResourceKeyNotFound0": "Clé de la ressource de type chaîne introuvable : '{0}'", 16 | "loc.messages.PSLIB_TaskVariable0": "Variable de tâche '{0}'" 17 | } -------------------------------------------------------------------------------- /variabledehydration-task/v0/ps_modules/VstsTaskSdk/Strings/resources.resjson/it-IT/resources.resjson: -------------------------------------------------------------------------------- 1 | { 2 | "loc.messages.PSLIB_ContainerPathNotFound0": "Percorso del contenitore non trovato: '{0}'", 3 | "loc.messages.PSLIB_EndpointAuth0": "Credenziali dell'endpoint servizio '{0}'", 4 | "loc.messages.PSLIB_EndpointUrl0": "URL dell'endpoint servizio '{0}'", 5 | "loc.messages.PSLIB_EnumeratingSubdirectoriesFailedForPath0": "L'enumerazione delle sottodirectory per il percorso '{0}' non è riuscita", 6 | "loc.messages.PSLIB_FileNotFound0": "File non trovato: '{0}'", 7 | "loc.messages.PSLIB_Input0": "Input di '{0}'", 8 | "loc.messages.PSLIB_InvalidPattern0": "Criterio non valido: '{0}'", 9 | "loc.messages.PSLIB_LeafPathNotFound0": "Percorso foglia non trovato: '{0}'", 10 | "loc.messages.PSLIB_PathLengthNotReturnedFor0": "La normalizzazione o l'espansione del percorso non è riuscita. Il sottosistema Kernel32 non ha restituito la lunghezza del percorso per '{0}'", 11 | "loc.messages.PSLIB_PathNotFound0": "Percorso non trovato: '{0}'", 12 | "loc.messages.PSLIB_Process0ExitedWithCode1": "Il processo '{0}' è stato terminato ed è stato restituito il codice '{1}'.", 13 | "loc.messages.PSLIB_Required0": "Obbligatorio: {0}", 14 | "loc.messages.PSLIB_StringFormatFailed": "Errore nel formato della stringa.", 15 | "loc.messages.PSLIB_StringResourceKeyNotFound0": "La chiave della risorsa stringa non è stata trovata: '{0}'", 16 | "loc.messages.PSLIB_TaskVariable0": "Variabile dell'attività '{0}'" 17 | } -------------------------------------------------------------------------------- /variabledehydration-task/v0/ps_modules/VstsTaskSdk/Strings/resources.resjson/ja-jp/resources.resjson: -------------------------------------------------------------------------------- 1 | { 2 | "loc.messages.PSLIB_ContainerPathNotFound0": "コンテナーのパスが見つかりません: '{0}'", 3 | "loc.messages.PSLIB_EndpointAuth0": "'{0}' サービス エンドポイントの資格情報", 4 | "loc.messages.PSLIB_EndpointUrl0": "'{0}' サービス エンドポイントの URL", 5 | "loc.messages.PSLIB_EnumeratingSubdirectoriesFailedForPath0": "パス '{0}' のサブディレクトリを列挙できませんでした", 6 | "loc.messages.PSLIB_FileNotFound0": "ファイルが見つかりません: '{0}'", 7 | "loc.messages.PSLIB_Input0": "'{0}' 入力", 8 | "loc.messages.PSLIB_InvalidPattern0": "使用できないパターンです: '{0}'", 9 | "loc.messages.PSLIB_LeafPathNotFound0": "リーフ パスが見つかりません: '{0}'", 10 | "loc.messages.PSLIB_PathLengthNotReturnedFor0": "パスの正規化/展開に失敗しました。Kernel32 サブシステムからパス '{0}' の長さが返されませんでした", 11 | "loc.messages.PSLIB_PathNotFound0": "パスが見つかりません: '{0}'", 12 | "loc.messages.PSLIB_Process0ExitedWithCode1": "プロセス '{0}' がコード '{1}' で終了しました。", 13 | "loc.messages.PSLIB_Required0": "必要: {0}", 14 | "loc.messages.PSLIB_StringFormatFailed": "文字列のフォーマットに失敗しました。", 15 | "loc.messages.PSLIB_StringResourceKeyNotFound0": "文字列のリソース キーが見つかりません: '{0}'", 16 | "loc.messages.PSLIB_TaskVariable0": "'{0}' タスク変数" 17 | } -------------------------------------------------------------------------------- /variabledehydration-task/v0/ps_modules/VstsTaskSdk/Strings/resources.resjson/ko-KR/resources.resjson: -------------------------------------------------------------------------------- 1 | { 2 | "loc.messages.PSLIB_ContainerPathNotFound0": "컨테이너 경로를 찾을 수 없음: '{0}'", 3 | "loc.messages.PSLIB_EndpointAuth0": "'{0}' 서비스 끝점 자격 증명", 4 | "loc.messages.PSLIB_EndpointUrl0": "'{0}' 서비스 끝점 URL", 5 | "loc.messages.PSLIB_EnumeratingSubdirectoriesFailedForPath0": "경로에 대해 하위 디렉터리를 열거하지 못함: '{0}'", 6 | "loc.messages.PSLIB_FileNotFound0": "{0} 파일을 찾을 수 없습니다.", 7 | "loc.messages.PSLIB_Input0": "'{0}' 입력", 8 | "loc.messages.PSLIB_InvalidPattern0": "잘못된 패턴: '{0}'", 9 | "loc.messages.PSLIB_LeafPathNotFound0": "Leaf 경로를 찾을 수 없음: '{0}'", 10 | "loc.messages.PSLIB_PathLengthNotReturnedFor0": "경로 정규화/확장에 실패했습니다. 다음에 대해 Kernel32 subsystem에서 경로 길이를 반환하지 않음: '{0}'", 11 | "loc.messages.PSLIB_PathNotFound0": "경로를 찾을 수 없음: '{0}'", 12 | "loc.messages.PSLIB_Process0ExitedWithCode1": "'{1}' 코드로 '{0}' 프로세스가 종료되었습니다.", 13 | "loc.messages.PSLIB_Required0": "필수: {0}", 14 | "loc.messages.PSLIB_StringFormatFailed": "문자열을 포맷하지 못했습니다.", 15 | "loc.messages.PSLIB_StringResourceKeyNotFound0": "문자열 리소스 키를 찾을 수 없음: '{0}'", 16 | "loc.messages.PSLIB_TaskVariable0": "'{0}' 작업 변수" 17 | } -------------------------------------------------------------------------------- /variabledehydration-task/v0/ps_modules/VstsTaskSdk/Strings/resources.resjson/ru-RU/resources.resjson: -------------------------------------------------------------------------------- 1 | { 2 | "loc.messages.PSLIB_ContainerPathNotFound0": "Путь к контейнеру не найден: \"{0}\".", 3 | "loc.messages.PSLIB_EndpointAuth0": "Учетные данные конечной точки службы \"{0}\"", 4 | "loc.messages.PSLIB_EndpointUrl0": "URL-адрес конечной точки службы \"{0}\"", 5 | "loc.messages.PSLIB_EnumeratingSubdirectoriesFailedForPath0": "Сбой перечисления подкаталогов для пути: \"{0}\".", 6 | "loc.messages.PSLIB_FileNotFound0": "Файл не найден: \"{0}\".", 7 | "loc.messages.PSLIB_Input0": "Входные данные \"{0}\".", 8 | "loc.messages.PSLIB_InvalidPattern0": "Недопустимый шаблон: \"{0}\".", 9 | "loc.messages.PSLIB_LeafPathNotFound0": "Путь к конечному объекту не найден: \"{0}\".", 10 | "loc.messages.PSLIB_PathLengthNotReturnedFor0": "Сбой нормализации и расширения пути. Длина пути не была возвращена подсистемой Kernel32 для: \"{0}\".", 11 | "loc.messages.PSLIB_PathNotFound0": "Путь не найден: \"{0}\".", 12 | "loc.messages.PSLIB_Process0ExitedWithCode1": "Процесс \"{0}\" завершил работу с кодом \"{1}\".", 13 | "loc.messages.PSLIB_Required0": "Требуется: {0}", 14 | "loc.messages.PSLIB_StringFormatFailed": "Сбой формата строки.", 15 | "loc.messages.PSLIB_StringResourceKeyNotFound0": "Ключ ресурса строки не найден: \"{0}\".", 16 | "loc.messages.PSLIB_TaskVariable0": "Переменная задачи \"{0}\"" 17 | } -------------------------------------------------------------------------------- /variabledehydration-task/v0/ps_modules/VstsTaskSdk/Strings/resources.resjson/zh-CN/resources.resjson: -------------------------------------------------------------------------------- 1 | { 2 | "loc.messages.PSLIB_ContainerPathNotFound0": "找不到容器路径:“{0}”", 3 | "loc.messages.PSLIB_EndpointAuth0": "“{0}”服务终结点凭据", 4 | "loc.messages.PSLIB_EndpointUrl0": "“{0}”服务终结点 URL", 5 | "loc.messages.PSLIB_EnumeratingSubdirectoriesFailedForPath0": "枚举路径的子目录失败:“{0}”", 6 | "loc.messages.PSLIB_FileNotFound0": "找不到文件: {0}。", 7 | "loc.messages.PSLIB_Input0": "“{0}”输入", 8 | "loc.messages.PSLIB_InvalidPattern0": "无效的模式:“{0}”", 9 | "loc.messages.PSLIB_LeafPathNotFound0": "找不到叶路径:“{0}”", 10 | "loc.messages.PSLIB_PathLengthNotReturnedFor0": "路径规范化/扩展失败。路径长度不是由“{0}”的 Kernel32 子系统返回的", 11 | "loc.messages.PSLIB_PathNotFound0": "找不到路径:“{0}”", 12 | "loc.messages.PSLIB_Process0ExitedWithCode1": "过程“{0}”已退出,代码为“{1}”。", 13 | "loc.messages.PSLIB_Required0": "必需: {0}", 14 | "loc.messages.PSLIB_StringFormatFailed": "字符串格式无效。", 15 | "loc.messages.PSLIB_StringResourceKeyNotFound0": "找不到字符串资源关键字:“{0}”", 16 | "loc.messages.PSLIB_TaskVariable0": "“{0}”任务变量" 17 | } -------------------------------------------------------------------------------- /variabledehydration-task/v0/ps_modules/VstsTaskSdk/Strings/resources.resjson/zh-TW/resources.resjson: -------------------------------------------------------------------------------- 1 | { 2 | "loc.messages.PSLIB_ContainerPathNotFound0": "找不到容器路徑: '{0}'", 3 | "loc.messages.PSLIB_EndpointAuth0": "'{0}' 服務端點認證", 4 | "loc.messages.PSLIB_EndpointUrl0": "'{0}' 服務端點 URL", 5 | "loc.messages.PSLIB_EnumeratingSubdirectoriesFailedForPath0": "為路徑列舉子目錄失敗: '{0}'", 6 | "loc.messages.PSLIB_FileNotFound0": "找不到檔案: '{0}'", 7 | "loc.messages.PSLIB_Input0": "'{0}' 輸入", 8 | "loc.messages.PSLIB_InvalidPattern0": "模式無效: '{0}'", 9 | "loc.messages.PSLIB_LeafPathNotFound0": "找不到分葉路徑: '{0}'", 10 | "loc.messages.PSLIB_PathLengthNotReturnedFor0": "路徑正規化/展開失敗。Kernel32 子系統未傳回 '{0}' 的路徑長度", 11 | "loc.messages.PSLIB_PathNotFound0": "找不到路徑: '{0}'", 12 | "loc.messages.PSLIB_Process0ExitedWithCode1": "處理序 '{0}' 以返回碼 '{1}' 結束。", 13 | "loc.messages.PSLIB_Required0": "必要項: {0}", 14 | "loc.messages.PSLIB_StringFormatFailed": "字串格式失敗。", 15 | "loc.messages.PSLIB_StringResourceKeyNotFound0": "找不到字串資源索引鍵: '{0}'", 16 | "loc.messages.PSLIB_TaskVariable0": "'{0}' 工作變數" 17 | } -------------------------------------------------------------------------------- /variabledehydration-task/v0/ps_modules/VstsTaskSdk/ToolFunctions.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Asserts that a path exists. Throws if the path does not exist. 4 | 5 | .PARAMETER PassThru 6 | True to return the path. 7 | #> 8 | function Assert-Path { 9 | [CmdletBinding()] 10 | param( 11 | [Parameter(Mandatory = $true)] 12 | [string]$LiteralPath, 13 | [Microsoft.PowerShell.Commands.TestPathType]$PathType = [Microsoft.PowerShell.Commands.TestPathType]::Any, 14 | [switch]$PassThru) 15 | 16 | if ($PathType -eq [Microsoft.PowerShell.Commands.TestPathType]::Any) { 17 | Write-Verbose "Asserting path exists: '$LiteralPath'" 18 | } else { 19 | Write-Verbose "Asserting $("$PathType".ToLowerInvariant()) path exists: '$LiteralPath'" 20 | } 21 | 22 | if (Test-Path -LiteralPath $LiteralPath -PathType $PathType) { 23 | if ($PassThru) { 24 | return $LiteralPath 25 | } 26 | 27 | return 28 | } 29 | 30 | $resourceKey = switch ($PathType) { 31 | ([Microsoft.PowerShell.Commands.TestPathType]::Container) { "PSLIB_ContainerPathNotFound0" ; break } 32 | ([Microsoft.PowerShell.Commands.TestPathType]::Leaf) { "PSLIB_LeafPathNotFound0" ; break } 33 | default { "PSLIB_PathNotFound0" } 34 | } 35 | 36 | throw (Get-LocString -Key $resourceKey -ArgumentList $LiteralPath) 37 | } 38 | 39 | <# 40 | .SYNOPSIS 41 | Executes an external program. 42 | 43 | .DESCRIPTION 44 | Executes an external program and waits for the process to exit. 45 | 46 | After calling this command, the exit code of the process can be retrieved from the variable $LASTEXITCODE. 47 | 48 | .PARAMETER Encoding 49 | This parameter not required for most scenarios. Indicates how to interpret the encoding from the external program. An example use case would be if an external program outputs UTF-16 XML and the output needs to be parsed. 50 | 51 | .PARAMETER RequireExitCodeZero 52 | Indicates whether to write an error to the error pipeline if the exit code is not zero. 53 | #> 54 | function Invoke-Tool { # TODO: RENAME TO INVOKE-PROCESS? 55 | [CmdletBinding()] 56 | param( 57 | [ValidatePattern('^[^\r\n]*$')] 58 | [Parameter(Mandatory = $true)] 59 | [string]$FileName, 60 | [ValidatePattern('^[^\r\n]*$')] 61 | [Parameter()] 62 | [string]$Arguments, 63 | [string]$WorkingDirectory, 64 | [System.Text.Encoding]$Encoding, 65 | [switch]$RequireExitCodeZero) 66 | 67 | Trace-EnteringInvocation $MyInvocation 68 | $isPushed = $false 69 | $originalEncoding = $null 70 | try { 71 | if ($Encoding) { 72 | $originalEncoding = [System.Console]::OutputEncoding 73 | [System.Console]::OutputEncoding = $Encoding 74 | } 75 | 76 | if ($WorkingDirectory) { 77 | Push-Location -LiteralPath $WorkingDirectory -ErrorAction Stop 78 | $isPushed = $true 79 | } 80 | 81 | $FileName = $FileName.Replace('"', '').Replace("'", "''") 82 | Write-Host "##[command]""$FileName"" $Arguments" 83 | Invoke-Expression "& '$FileName' --% $Arguments" 84 | Write-Verbose "Exit code: $LASTEXITCODE" 85 | if ($RequireExitCodeZero -and $LASTEXITCODE -ne 0) { 86 | Write-Error (Get-LocString -Key PSLIB_Process0ExitedWithCode1 -ArgumentList ([System.IO.Path]::GetFileName($FileName)), $LASTEXITCODE) 87 | } 88 | } finally { 89 | if ($originalEncoding) { 90 | [System.Console]::OutputEncoding = $originalEncoding 91 | } 92 | 93 | if ($isPushed) { 94 | Pop-Location 95 | } 96 | 97 | Trace-LeavingInvocation $MyInvocation 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /variabledehydration-task/v0/ps_modules/VstsTaskSdk/TraceFunctions.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Writes verbose information about the invocation being entered. 4 | 5 | .DESCRIPTION 6 | Used to trace verbose information when entering a function/script. Writes an entering message followed by a short description of the invocation. Additionally each bound parameter and unbound argument is also traced. 7 | 8 | .PARAMETER Parameter 9 | Wildcard pattern to control which bound parameters are traced. 10 | #> 11 | function Trace-EnteringInvocation { 12 | [CmdletBinding()] 13 | param( 14 | [Parameter(Mandatory = $true)] 15 | [System.Management.Automation.InvocationInfo]$InvocationInfo, 16 | [string[]]$Parameter = '*') 17 | 18 | Write-Verbose "Entering $(Get-InvocationDescription $InvocationInfo)." 19 | $OFS = ", " 20 | if ($InvocationInfo.BoundParameters.Count -and $Parameter.Count) { 21 | if ($Parameter.Count -eq 1 -and $Parameter[0] -eq '*') { 22 | # Trace all parameters. 23 | foreach ($key in $InvocationInfo.BoundParameters.Keys) { 24 | Write-Verbose " $($key): '$($InvocationInfo.BoundParameters[$key])'" 25 | } 26 | } else { 27 | # Trace matching parameters. 28 | foreach ($key in $InvocationInfo.BoundParameters.Keys) { 29 | foreach ($p in $Parameter) { 30 | if ($key -like $p) { 31 | Write-Verbose " $($key): '$($InvocationInfo.BoundParameters[$key])'" 32 | break 33 | } 34 | } 35 | } 36 | } 37 | } 38 | 39 | # Trace all unbound arguments. 40 | if (@($InvocationInfo.UnboundArguments).Count) { 41 | for ($i = 0 ; $i -lt $InvocationInfo.UnboundArguments.Count ; $i++) { 42 | Write-Verbose " args[$i]: '$($InvocationInfo.UnboundArguments[$i])'" 43 | } 44 | } 45 | } 46 | 47 | <# 48 | .SYNOPSIS 49 | Writes verbose information about the invocation being left. 50 | 51 | .DESCRIPTION 52 | Used to trace verbose information when leaving a function/script. Writes a leaving message followed by a short description of the invocation. 53 | #> 54 | function Trace-LeavingInvocation { 55 | [CmdletBinding()] 56 | param( 57 | [Parameter(Mandatory = $true)] 58 | [System.Management.Automation.InvocationInfo]$InvocationInfo) 59 | 60 | Write-Verbose "Leaving $(Get-InvocationDescription $InvocationInfo)." 61 | } 62 | 63 | <# 64 | .SYNOPSIS 65 | Writes verbose information about paths. 66 | 67 | .DESCRIPTION 68 | Writes verbose information about the paths. The paths are sorted and a the common root is written only once, followed by each relative path. 69 | 70 | .PARAMETER PassThru 71 | Indicates whether to return the sorted paths. 72 | #> 73 | function Trace-Path { 74 | [CmdletBinding()] 75 | param( 76 | [string[]]$Path, 77 | [switch]$PassThru) 78 | 79 | if ($Path.Count -eq 0) { 80 | Write-Verbose "No paths." 81 | if ($PassThru) { 82 | $Path 83 | } 84 | } elseif ($Path.Count -eq 1) { 85 | Write-Verbose "Path: $($Path[0])" 86 | if ($PassThru) { 87 | $Path 88 | } 89 | } else { 90 | # Find the greatest common root. 91 | $sorted = $Path | Sort-Object 92 | $firstPath = $sorted[0].ToCharArray() 93 | $lastPath = $sorted[-1].ToCharArray() 94 | $commonEndIndex = 0 95 | $j = if ($firstPath.Length -lt $lastPath.Length) { $firstPath.Length } else { $lastPath.Length } 96 | for ($i = 0 ; $i -lt $j ; $i++) { 97 | if ($firstPath[$i] -eq $lastPath[$i]) { 98 | if ($firstPath[$i] -eq '\') { 99 | $commonEndIndex = $i 100 | } 101 | } else { 102 | break 103 | } 104 | } 105 | 106 | if ($commonEndIndex -eq 0) { 107 | # No common root. 108 | Write-Verbose "Paths:" 109 | foreach ($p in $sorted) { 110 | Write-Verbose " $p" 111 | } 112 | } else { 113 | Write-Verbose "Paths: $($Path[0].Substring(0, $commonEndIndex + 1))" 114 | foreach ($p in $sorted) { 115 | Write-Verbose " $($p.Substring($commonEndIndex + 1))" 116 | } 117 | } 118 | 119 | if ($PassThru) { 120 | $sorted 121 | } 122 | } 123 | } 124 | 125 | ######################################## 126 | # Private functions. 127 | ######################################## 128 | function Get-InvocationDescription { 129 | [CmdletBinding()] 130 | param([System.Management.Automation.InvocationInfo]$InvocationInfo) 131 | 132 | if ($InvocationInfo.MyCommand.Path) { 133 | $InvocationInfo.MyCommand.Path 134 | } elseif ($InvocationInfo.MyCommand.Name) { 135 | $InvocationInfo.MyCommand.Name 136 | } else { 137 | $InvocationInfo.MyCommand.CommandType 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /variabledehydration-task/v0/ps_modules/VstsTaskSdk/VstsTaskSdk.psd1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkdAgility/azure-devops-variable-tools/cc71f5f1648177772a8bb80473407752c50c0858/variabledehydration-task/v0/ps_modules/VstsTaskSdk/VstsTaskSdk.psd1 -------------------------------------------------------------------------------- /variabledehydration-task/v0/ps_modules/VstsTaskSdk/VstsTaskSdk.psm1: -------------------------------------------------------------------------------- 1 | [CmdletBinding()] 2 | param( 3 | [ValidateNotNull()] 4 | [Parameter()] 5 | [hashtable]$ModuleParameters = @{ }) 6 | 7 | if ($host.Name -ne 'ConsoleHost') { 8 | Write-Warning "VstsTaskSdk is designed for use with powershell.exe (ConsoleHost). Output may be different when used with other hosts." 9 | } 10 | 11 | # Private module variables. 12 | [bool]$script:nonInteractive = "$($ModuleParameters['NonInteractive'])" -eq 'true' 13 | Write-Verbose "NonInteractive: $script:nonInteractive" 14 | 15 | # Import/export functions. 16 | . "$PSScriptRoot\FindFunctions.ps1" 17 | . "$PSScriptRoot\InputFunctions.ps1" 18 | . "$PSScriptRoot\LocalizationFunctions.ps1" 19 | . "$PSScriptRoot\LoggingCommandFunctions.ps1" 20 | . "$PSScriptRoot\LongPathFunctions.ps1" 21 | . "$PSScriptRoot\ServerOMFunctions.ps1" 22 | . "$PSScriptRoot\ToolFunctions.ps1" 23 | . "$PSScriptRoot\TraceFunctions.ps1" 24 | . "$PSScriptRoot\OutFunctions.ps1" # Load the out functions after all of the other functions are loaded. 25 | Export-ModuleMember -Function @( 26 | # Find functions. 27 | 'Find-Files' 28 | # Input functions. 29 | 'Get-Endpoint' 30 | 'Get-Input' 31 | 'Get-TaskVariable' 32 | 'Get-TaskVariableInfo' 33 | 'Set-TaskVariable' 34 | # Localization functions. 35 | 'Get-LocString' 36 | 'Import-LocStrings' 37 | # Logging command functions. 38 | 'Write-AddAttachment' 39 | 'Write-AddBuildTag' 40 | 'Write-AssociateArtifact' 41 | 'Write-LogDetail' 42 | 'Write-SetProgress' 43 | 'Write-SetResult' 44 | 'Write-SetSecret' 45 | 'Write-SetVariable' 46 | 'Write-TaskDebug' 47 | 'Write-TaskError' 48 | 'Write-TaskVerbose' 49 | 'Write-TaskWarning' 50 | 'Write-UpdateBuildNumber' 51 | 'Write-UploadArtifact' 52 | 'Write-UploadBuildLog' 53 | # Out functions. 54 | 'Out-Default' 55 | # Server OM functions. 56 | 'Get-AssemblyReference' 57 | 'Get-TfsClientCredentials' 58 | 'Get-TfsService' 59 | 'Get-VssCredentials' 60 | 'Get-VssHttpClient' 61 | # Tool functions. 62 | 'Assert-Path' 63 | 'Invoke-Tool' 64 | # Trace functions. 65 | 'Trace-EnteringInvocation' 66 | 'Trace-LeavingInvocation' 67 | 'Trace-Path' 68 | ) 69 | 70 | # Special internal exception type to control the flow. Not currently intended 71 | # for public usage and subject to change. If the type has already 72 | # been loaded once, then it is not loaded again. 73 | Write-Verbose "Adding exceptions types." 74 | Add-Type -WarningAction SilentlyContinue -Debug:$false -TypeDefinition @' 75 | namespace VstsTaskSdk 76 | { 77 | public class TerminationException : System.Exception 78 | { 79 | public TerminationException(System.String message) : base(message) { } 80 | } 81 | } 82 | '@ 83 | 84 | # Override Out-Default globally. 85 | $null = New-Item -Force -Path "function:\global:Out-Default" -Value (Get-Command -CommandType Function -Name Out-Default -ListImported) 86 | New-Alias -Name Out-Default -Value "global:Out-Default" -Scope global 87 | 88 | # Perform some initialization in a script block to enable merging the pipelines. 89 | $scriptText = @" 90 | # Load the SDK resource strings. 91 | Import-LocStrings "$PSScriptRoot\lib.json" 92 | 93 | # Load the module that contains ConvertTo-SecureString. 94 | if (!(Get-Module -Name Microsoft.PowerShell.Security)) { 95 | Write-Verbose "Importing the module 'Microsoft.PowerShell.Security'." 96 | Import-Module -Name Microsoft.PowerShell.Security 2>&1 | 97 | ForEach-Object { 98 | if (`$_ -is [System.Management.Automation.ErrorRecord]) { 99 | Write-Verbose `$_.Exception.Message 100 | } else { 101 | ,`$_ 102 | } 103 | } 104 | } 105 | "@ 106 | . ([scriptblock]::Create($scriptText)) 2>&1 3>&1 4>&1 5>&1 | Out-Default 107 | 108 | # Create Invoke-VstsTaskScript in a special way so it is not bound to the module. 109 | # Otherwise calling the task script block would run within the module context. 110 | # 111 | # An alternative way to solve the problem is to close the script block (i.e. closure). 112 | # However, that introduces a different problem. Closed script blocks are created within 113 | # a dynamic module. Each module gets it's own session state separate from the global 114 | # session state. When running in a regular script context, Import-Module calls import 115 | # the target module into the global session state. When running in a module context, 116 | # Import-Module calls import the target module into the caller module's session state. 117 | # 118 | # The goal of a task may include executing ad-hoc scripts. Therefore, task scripts 119 | # should run in regular script context. The end user specifying an ad-hoc script expects 120 | # the module import rules to be consistent with the default behavior (i.e. imported 121 | # into the global session state). 122 | $null = New-Item -Force -Path "function:\global:Invoke-VstsTaskScript" -Value ([scriptblock]::Create(@' 123 | [CmdletBinding()] 124 | param( 125 | [Parameter(Mandatory = $true)] 126 | [scriptblock]$ScriptBlock) 127 | 128 | try { 129 | $global:ErrorActionPreference = 'Stop' 130 | 131 | # Initialize the environment. 132 | $vstsModule = Get-Module -Name VstsTaskSdk 133 | Write-Verbose "$($vstsModule.Name) $($vstsModule.Version) commit $($vstsModule.PrivateData.PSData.CommitHash)" 4>&1 | Out-Default 134 | & $vstsModule Initialize-Inputs 4>&1 | Out-Default 135 | 136 | # Remove the local variable before calling the user's script. 137 | Remove-Variable -Name vstsModule 138 | 139 | # Call the user's script. 140 | $ScriptBlock | 141 | ForEach-Object { 142 | # Remove the scriptblock variable before calling it. 143 | Remove-Variable -Name ScriptBlock 144 | & $_ 2>&1 3>&1 4>&1 5>&1 | Out-Default 145 | } 146 | } catch [VstsTaskSdk.TerminationException] { 147 | # Special internal exception type to control the flow. Not currently intended 148 | # for public usage and subject to change. 149 | Write-Verbose "Task script terminated." 4>&1 | Out-Default 150 | } catch { 151 | Write-Verbose "Caught exception from task script." 4>&1 | Out-Default 152 | $_ | Out-Default 153 | Write-Host "##vso[task.complete result=Failed]" 154 | } 155 | '@)) 156 | -------------------------------------------------------------------------------- /variabledehydration-task/v0/ps_modules/VstsTaskSdk/lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "messages": { 3 | "PSLIB_ContainerPathNotFound0": "Container path not found: '{0}'", 4 | "PSLIB_EndpointAuth0": "'{0}' service endpoint credentials", 5 | "PSLIB_EndpointUrl0": "'{0}' service endpoint URL", 6 | "PSLIB_EnumeratingSubdirectoriesFailedForPath0": "Enumerating subdirectories failed for path: '{0}'", 7 | "PSLIB_FileNotFound0": "File not found: '{0}'", 8 | "PSLIB_Input0": "'{0}' input", 9 | "PSLIB_InvalidPattern0": "Invalid pattern: '{0}'", 10 | "PSLIB_LeafPathNotFound0": "Leaf path not found: '{0}'", 11 | "PSLIB_PathLengthNotReturnedFor0": "Path normalization/expansion failed. The path length was not returned by the Kernel32 subsystem for: '{0}'", 12 | "PSLIB_PathNotFound0": "Path not found: '{0}'", 13 | "PSLIB_Process0ExitedWithCode1": "Process '{0}' exited with code '{1}'.", 14 | "PSLIB_Required0": "Required: {0}", 15 | "PSLIB_StringFormatFailed": "String format failed.", 16 | "PSLIB_StringResourceKeyNotFound0": "String resource key not found: '{0}'", 17 | "PSLIB_TaskVariable0": "'{0}' task variable" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /variabledehydration-task/v0/task.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "94fd260a-77ed-4c97-a4aa-2a27039e29b8", 3 | "name": "variabledehydration", 4 | "friendlyName": "Variable Save Task", 5 | "description": "Saves the build variables as a .json file so that you can use it later.", 6 | "helpMarkDown": "v#{GitVersion.FullSemVer}# [More Information](https://dev.azure.com/nkdagility/_git/Azure-DevOps-Variable-Tools?path=%2FREADME.md)", 7 | "category": "Utility", 8 | "visibility": [ 9 | "Build", 10 | "Deploy" 11 | ], 12 | "author": "naked Agility - Martin Hinshelwood", 13 | "version": { 14 | "Major": "#{GitVersion.Major}#", 15 | "Minor": "#{GitVersion.Minor}#", 16 | "Patch": "#{GitVersion.Patch}#" 17 | }, 18 | "minimumAgentVersion": "2.103.0", 19 | "groups": [ 20 | { 21 | "name": "missing", 22 | "displayName": "Missing variables", 23 | "isExpanded": true 24 | } 25 | ], 26 | "inputs": [ 27 | { 28 | "name": "prefixes", 29 | "type": "string", 30 | "label": "Prefixes", 31 | "defaultValue": "GITVERSION,BUILD", 32 | "required": true, 33 | "helpMarkDown": "Comma delimited list of build prefixes to save. Since we have to save environmental Variables we need to filter." 34 | }, 35 | { 36 | "name": "outpath", 37 | "type": "filePath", 38 | "label": "Output Path", 39 | "defaultValue": "$(Build.ArtifactStagingDirectory)", 40 | "required": true, 41 | "helpMarkDown": "Select a folder to store the dehydrated data." 42 | } 43 | ], 44 | "instanceNameFormat": "Save Build Variables $(prefixes)", 45 | "execution": { 46 | "PowerShell3": { 47 | "target": "$(currentDirectory)\\dehydrate-variables.ps1", 48 | "argumentFormat": "", 49 | "workingDirectory": "$(System.DefaultWorkingDirectory)" 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /variablerehydration-task/v0/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkdAgility/azure-devops-variable-tools/cc71f5f1648177772a8bb80473407752c50c0858/variablerehydration-task/v0/icon.png -------------------------------------------------------------------------------- /variablerehydration-task/v0/ps_modules/VstsTaskSdk/FindFunctions.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Finds files or directories. 4 | 5 | .DESCRIPTION 6 | Finds files or directories using advanced pattern matching. 7 | 8 | .PARAMETER LiteralDirectory 9 | Directory to search. 10 | 11 | .PARAMETER LegacyPattern 12 | Proprietary pattern format. The LiteralDirectory parameter is used to root any unrooted patterns. 13 | 14 | Separate multiple patterns using ";". Escape actual ";" in the path by using ";;". 15 | "?" indicates a wildcard that represents any single character within a path segment. 16 | "*" indicates a wildcard that represents zero or more characters within a path segment. 17 | "**" as the entire path segment indicates a recursive search. 18 | "**" within a path segment indicates a recursive intersegment wildcard. 19 | "+:" (can be omitted) indicates an include pattern. 20 | "-:" indicates an exclude pattern. 21 | 22 | The result is from the command is a union of all the matches from the include patterns, minus the matches from the exclude patterns. 23 | 24 | .PARAMETER IncludeFiles 25 | Indicates whether to include files in the results. 26 | 27 | If neither IncludeFiles or IncludeDirectories is set, then IncludeFiles is assumed. 28 | 29 | .PARAMETER IncludeDirectories 30 | Indicates whether to include directories in the results. 31 | 32 | If neither IncludeFiles or IncludeDirectories is set, then IncludeFiles is assumed. 33 | 34 | .PARAMETER Force 35 | Indicates whether to include hidden items. 36 | 37 | .EXAMPLE 38 | Find-VstsFiles -LegacyPattern "C:\Directory\Is?Match.txt" 39 | 40 | Given: 41 | C:\Directory\Is1Match.txt 42 | C:\Directory\Is2Match.txt 43 | C:\Directory\IsNotMatch.txt 44 | 45 | Returns: 46 | C:\Directory\Is1Match.txt 47 | C:\Directory\Is2Match.txt 48 | 49 | .EXAMPLE 50 | Find-VstsFiles -LegacyPattern "C:\Directory\Is*Match.txt" 51 | 52 | Given: 53 | C:\Directory\IsOneMatch.txt 54 | C:\Directory\IsTwoMatch.txt 55 | C:\Directory\NonMatch.txt 56 | 57 | Returns: 58 | C:\Directory\IsOneMatch.txt 59 | C:\Directory\IsTwoMatch.txt 60 | 61 | .EXAMPLE 62 | Find-VstsFiles -LegacyPattern "C:\Directory\**\Match.txt" 63 | 64 | Given: 65 | C:\Directory\Match.txt 66 | C:\Directory\NotAMatch.txt 67 | C:\Directory\SubDir\Match.txt 68 | C:\Directory\SubDir\SubSubDir\Match.txt 69 | 70 | Returns: 71 | C:\Directory\Match.txt 72 | C:\Directory\SubDir\Match.txt 73 | C:\Directory\SubDir\SubSubDir\Match.txt 74 | 75 | .EXAMPLE 76 | Find-VstsFiles -LegacyPattern "C:\Directory\**" 77 | 78 | Given: 79 | C:\Directory\One.txt 80 | C:\Directory\SubDir\Two.txt 81 | C:\Directory\SubDir\SubSubDir\Three.txt 82 | 83 | Returns: 84 | C:\Directory\One.txt 85 | C:\Directory\SubDir\Two.txt 86 | C:\Directory\SubDir\SubSubDir\Three.txt 87 | 88 | .EXAMPLE 89 | Find-VstsFiles -LegacyPattern "C:\Directory\Sub**Match.txt" 90 | 91 | Given: 92 | C:\Directory\IsNotAMatch.txt 93 | C:\Directory\SubDir\IsAMatch.txt 94 | C:\Directory\SubDir\IsNot.txt 95 | C:\Directory\SubDir\SubSubDir\IsAMatch.txt 96 | C:\Directory\SubDir\SubSubDir\IsNot.txt 97 | 98 | Returns: 99 | C:\Directory\SubDir\IsAMatch.txt 100 | C:\Directory\SubDir\SubSubDir\IsAMatch.txt 101 | #> 102 | function Find-Files { 103 | [CmdletBinding()] 104 | param( 105 | [ValidateNotNullOrEmpty()] 106 | [Parameter()] 107 | [string]$LiteralDirectory, 108 | [Parameter(Mandatory = $true)] 109 | [string]$LegacyPattern, 110 | [switch]$IncludeFiles, 111 | [switch]$IncludeDirectories, 112 | [switch]$Force) 113 | 114 | Trace-EnteringInvocation $MyInvocation 115 | if (!$IncludeFiles -and !$IncludeDirectories) { 116 | $IncludeFiles = $true 117 | } 118 | 119 | $includePatterns = New-Object System.Collections.Generic.List[string] 120 | $excludePatterns = New-Object System.Collections.Generic.List[System.Text.RegularExpressions.Regex] 121 | $LegacyPattern = $LegacyPattern.Replace(';;', "`0") 122 | foreach ($pattern in $LegacyPattern.Split(';', [System.StringSplitOptions]::RemoveEmptyEntries)) { 123 | $pattern = $pattern.Replace("`0", ';') 124 | $isIncludePattern = Test-IsIncludePattern -Pattern ([ref]$pattern) 125 | if ($LiteralDirectory -and !([System.IO.Path]::IsPathRooted($pattern))) { 126 | # Use the root directory provided to make the pattern a rooted path. 127 | $pattern = [System.IO.Path]::Combine($LiteralDirectory, $pattern) 128 | } 129 | 130 | # Validate pattern does not end with a \. 131 | if ($pattern[$pattern.Length - 1] -eq [System.IO.Path]::DirectorySeparatorChar) { 132 | throw (Get-LocString -Key PSLIB_InvalidPattern0 -ArgumentList $pattern) 133 | } 134 | 135 | if ($isIncludePattern) { 136 | $includePatterns.Add($pattern) 137 | } else { 138 | $excludePatterns.Add((Convert-PatternToRegex -Pattern $pattern)) 139 | } 140 | } 141 | 142 | $count = 0 143 | foreach ($path in (Get-MatchingItems -IncludePatterns $includePatterns -ExcludePatterns $excludePatterns -IncludeFiles:$IncludeFiles -IncludeDirectories:$IncludeDirectories -Force:$Force)) { 144 | $count++ 145 | $path 146 | } 147 | 148 | Write-Verbose "Total found: $count" 149 | Trace-LeavingInvocation $MyInvocation 150 | } 151 | 152 | ######################################## 153 | # Private functions. 154 | ######################################## 155 | function Convert-PatternToRegex { 156 | [CmdletBinding()] 157 | param([string]$Pattern) 158 | 159 | $Pattern = [regex]::Escape($Pattern.Replace('\', '/')). # Normalize separators and regex escape. 160 | Replace('/\*\*/', '((/.+/)|(/))'). # Replace directory globstar. 161 | Replace('\*\*', '.*'). # Replace remaining globstars with a wildcard that can span directory separators. 162 | Replace('\*', '[^/]*'). # Replace asterisks with a wildcard that cannot span directory separators. 163 | Replace('\?', '.') # Replace single character wildcards. 164 | New-Object regex -ArgumentList "^$Pattern`$", ([System.Text.RegularExpressions.RegexOptions]::IgnoreCase) 165 | } 166 | 167 | function Get-FileNameFilter { 168 | [CmdletBinding()] 169 | param([string]$Pattern) 170 | 171 | $index = $Pattern.LastIndexOf('\') 172 | if ($index -eq -1 -or # Pattern does not contain a backslash. 173 | !($Pattern = $Pattern.Substring($index + 1)) -or # Pattern ends in a backslash. 174 | $Pattern.Contains('**')) # Last segment contains an inter-segment wildcard. 175 | { 176 | return '*' 177 | } 178 | 179 | return $Pattern 180 | } 181 | 182 | function Get-MatchingItems { 183 | [CmdletBinding()] 184 | param( 185 | [System.Collections.Generic.List[string]]$IncludePatterns, 186 | [System.Collections.Generic.List[regex]]$ExcludePatterns, 187 | [switch]$IncludeFiles, 188 | [switch]$IncludeDirectories, 189 | [switch]$Force) 190 | 191 | Trace-EnteringInvocation $MyInvocation 192 | $allFiles = New-Object System.Collections.Generic.HashSet[string] 193 | foreach ($pattern in $IncludePatterns) { 194 | $pathPrefix = Get-PathPrefix -Pattern $pattern 195 | $fileNameFilter = Get-FileNameFilter -Pattern $pattern 196 | $patternRegex = Convert-PatternToRegex -Pattern $pattern 197 | # Iterate over the directories and files under the pathPrefix. 198 | Get-PathIterator -Path $pathPrefix -Filter $fileNameFilter -IncludeFiles:$IncludeFiles -IncludeDirectories:$IncludeDirectories -Force:$Force | 199 | ForEach-Object { 200 | # Normalize separators. 201 | $normalizedPath = $_.Replace('\', '/') 202 | # **/times/** will not match C:/fun/times because there isn't a trailing slash. 203 | # So try both if including directories. 204 | $alternatePath = "$normalizedPath/" 205 | 206 | $isMatch = $false 207 | if ($patternRegex.IsMatch($normalizedPath) -or ($IncludeDirectories -and $patternRegex.IsMatch($alternatePath))) { 208 | $isMatch = $true 209 | 210 | # Test whether the path should be excluded. 211 | foreach ($regex in $ExcludePatterns) { 212 | if ($regex.IsMatch($normalizedPath) -or ($IncludeDirectories -and $regex.IsMatch($alternatePath))) { 213 | $isMatch = $false 214 | break 215 | } 216 | } 217 | } 218 | 219 | if ($isMatch) { 220 | $null = $allFiles.Add($_) 221 | } 222 | } 223 | } 224 | 225 | Trace-Path -Path $allFiles -PassThru 226 | Trace-LeavingInvocation $MyInvocation 227 | } 228 | 229 | function Get-PathIterator { 230 | [CmdletBinding()] 231 | param( 232 | [string]$Path, 233 | [string]$Filter, 234 | [switch]$IncludeFiles, 235 | [switch]$IncludeDirectories, 236 | [switch]$Force) 237 | 238 | if (!$Path) { 239 | return 240 | } 241 | 242 | if ($IncludeDirectories) { 243 | $Path 244 | } 245 | 246 | Get-DirectoryChildItem -Path $Path -Filter $Filter -Force:$Force -Recurse | 247 | ForEach-Object { 248 | if ($_.Attributes.HasFlag([VstsTaskSdk.FS.Attributes]::Directory)) { 249 | if ($IncludeDirectories) { 250 | $_.FullName 251 | } 252 | } elseif ($IncludeFiles) { 253 | $_.FullName 254 | } 255 | } 256 | } 257 | 258 | function Get-PathPrefix { 259 | [CmdletBinding()] 260 | param([string]$Pattern) 261 | 262 | $index = $Pattern.IndexOfAny([char[]]@('*'[0], '?'[0])) 263 | if ($index -eq -1) { 264 | # If no wildcards are found, return the directory name portion of the path. 265 | # If there is no directory name (file name only in pattern), this will return empty string. 266 | return [System.IO.Path]::GetDirectoryName($Pattern) 267 | } 268 | 269 | [System.IO.Path]::GetDirectoryName($Pattern.Substring(0, $index)) 270 | } 271 | 272 | function Test-IsIncludePattern { 273 | [CmdletBinding()] 274 | param( 275 | [Parameter(Mandatory = $true)] 276 | [ref]$Pattern) 277 | 278 | # Include patterns start with +: or anything except -: 279 | # Exclude patterns start with -: 280 | if ($Pattern.value.StartsWith("+:")) { 281 | # Remove the prefix. 282 | $Pattern.value = $Pattern.value.Substring(2) 283 | $true 284 | } elseif ($Pattern.value.StartsWith("-:")) { 285 | # Remove the prefix. 286 | $Pattern.value = $Pattern.value.Substring(2) 287 | $false 288 | } else { 289 | # No prefix, so leave the string alone. 290 | $true; 291 | } 292 | } 293 | -------------------------------------------------------------------------------- /variablerehydration-task/v0/ps_modules/VstsTaskSdk/InputFunctions.ps1: -------------------------------------------------------------------------------- 1 | # Hash table of known variable info. The formatted env var name is the lookup key. 2 | # 3 | # The purpose of this hash table is to keep track of known variables. The hash table 4 | # needs to be maintained for multiple reasons: 5 | # 1) to distinguish between env vars and job vars 6 | # 2) to distinguish between secret vars and public 7 | # 3) to know the real variable name and not just the formatted env var name. 8 | $script:knownVariables = @{ } 9 | $script:vault = @{ } 10 | 11 | <# 12 | .SYNOPSIS 13 | Gets an endpoint. 14 | 15 | .DESCRIPTION 16 | Gets an endpoint object for the specified endpoint name. The endpoint is returned as an object with three properties: Auth, Data, and Url. 17 | 18 | The Data property requires a 1.97 agent or higher. 19 | 20 | .PARAMETER Require 21 | Writes an error to the error pipeline if the endpoint is not found. 22 | #> 23 | function Get-Endpoint { 24 | [CmdletBinding()] 25 | param( 26 | [Parameter(Mandatory = $true)] 27 | [string]$Name, 28 | [switch]$Require) 29 | 30 | $originalErrorActionPreference = $ErrorActionPreference 31 | try { 32 | $ErrorActionPreference = 'Stop' 33 | 34 | # Get the URL. 35 | $description = Get-LocString -Key PSLIB_EndpointUrl0 -ArgumentList $Name 36 | $key = "ENDPOINT_URL_$Name" 37 | $url = Get-VaultValue -Description $description -Key $key -Require:$Require 38 | 39 | # Get the auth object. 40 | $description = Get-LocString -Key PSLIB_EndpointAuth0 -ArgumentList $Name 41 | $key = "ENDPOINT_AUTH_$Name" 42 | if ($auth = (Get-VaultValue -Description $description -Key $key -Require:$Require)) { 43 | $auth = ConvertFrom-Json -InputObject $auth 44 | } 45 | 46 | # Get the data. 47 | $description = "'$Name' service endpoint data" 48 | $key = "ENDPOINT_DATA_$Name" 49 | if ($data = (Get-VaultValue -Description $description -Key $key)) { 50 | $data = ConvertFrom-Json -InputObject $data 51 | } 52 | 53 | # Return the endpoint. 54 | if ($url -or $auth -or $data) { 55 | New-Object -TypeName psobject -Property @{ 56 | Url = $url 57 | Auth = $auth 58 | Data = $data 59 | } 60 | } 61 | } catch { 62 | $ErrorActionPreference = $originalErrorActionPreference 63 | Write-Error $_ 64 | } 65 | } 66 | 67 | <# 68 | .SYNOPSIS 69 | Gets an input. 70 | 71 | .DESCRIPTION 72 | Gets the value for the specified input name. 73 | 74 | .PARAMETER AsBool 75 | Returns the value as a bool. Returns true if the value converted to a string is "1" or "true" (case insensitive); otherwise false. 76 | 77 | .PARAMETER AsInt 78 | Returns the value as an int. Returns the value converted to an int. Returns 0 if the conversion fails. 79 | 80 | .PARAMETER Default 81 | Default value to use if the input is null or empty. 82 | 83 | .PARAMETER Require 84 | Writes an error to the error pipeline if the input is null or empty. 85 | #> 86 | function Get-Input { 87 | [CmdletBinding(DefaultParameterSetName = 'Require')] 88 | param( 89 | [Parameter(Mandatory = $true)] 90 | [string]$Name, 91 | [Parameter(ParameterSetName = 'Default')] 92 | $Default, 93 | [Parameter(ParameterSetName = 'Require')] 94 | [switch]$Require, 95 | [switch]$AsBool, 96 | [switch]$AsInt) 97 | 98 | # Get the input from the vault. Splat the bound parameters hashtable. Splatting is required 99 | # in order to concisely invoke the correct parameter set. 100 | $null = $PSBoundParameters.Remove('Name') 101 | $description = Get-LocString -Key PSLIB_Input0 -ArgumentList $Name 102 | $key = "INPUT_$($Name.Replace(' ', '_').ToUpperInvariant())" 103 | Get-VaultValue @PSBoundParameters -Description $description -Key $key 104 | } 105 | 106 | <# 107 | .SYNOPSIS 108 | Gets a task variable. 109 | 110 | .DESCRIPTION 111 | Gets the value for the specified task variable. 112 | 113 | .PARAMETER AsBool 114 | Returns the value as a bool. Returns true if the value converted to a string is "1" or "true" (case insensitive); otherwise false. 115 | 116 | .PARAMETER AsInt 117 | Returns the value as an int. Returns the value converted to an int. Returns 0 if the conversion fails. 118 | 119 | .PARAMETER Default 120 | Default value to use if the input is null or empty. 121 | 122 | .PARAMETER Require 123 | Writes an error to the error pipeline if the input is null or empty. 124 | #> 125 | function Get-TaskVariable { 126 | [CmdletBinding(DefaultParameterSetName = 'Require')] 127 | param( 128 | [Parameter(Mandatory = $true)] 129 | [string]$Name, 130 | [Parameter(ParameterSetName = 'Default')] 131 | $Default, 132 | [Parameter(ParameterSetName = 'Require')] 133 | [switch]$Require, 134 | [switch]$AsBool, 135 | [switch]$AsInt) 136 | 137 | $originalErrorActionPreference = $ErrorActionPreference 138 | try { 139 | $ErrorActionPreference = 'Stop' 140 | $description = Get-LocString -Key PSLIB_TaskVariable0 -ArgumentList $Name 141 | $variableKey = Get-VariableKey -Name $Name 142 | if ($script:knownVariables.$variableKey.Secret) { 143 | # Get secret variable. Splatting is required to concisely invoke the correct parameter set. 144 | $null = $PSBoundParameters.Remove('Name') 145 | $vaultKey = "SECRET_$variableKey" 146 | Get-VaultValue @PSBoundParameters -Description $description -Key $vaultKey 147 | } else { 148 | # Get public variable. 149 | $item = $null 150 | $path = "Env:$variableKey" 151 | if ((Test-Path -LiteralPath $path) -and ($item = Get-Item -LiteralPath $path).Value) { 152 | # Intentionally empty. Value was successfully retrieved. 153 | } elseif (!$script:nonInteractive) { 154 | # The value wasn't found and the module is running in interactive dev mode. 155 | # Prompt for the value. 156 | Set-Item -LiteralPath $path -Value (Read-Host -Prompt $description) 157 | if (Test-Path -LiteralPath $path) { 158 | $item = Get-Item -LiteralPath $path 159 | } 160 | } 161 | 162 | # Get the converted value. Splatting is required to concisely invoke the correct parameter set. 163 | $null = $PSBoundParameters.Remove('Name') 164 | Get-Value @PSBoundParameters -Description $description -Key $variableKey -Value $item.Value 165 | } 166 | } catch { 167 | $ErrorActionPreference = $originalErrorActionPreference 168 | Write-Error $_ 169 | } 170 | } 171 | 172 | <# 173 | .SYNOPSIS 174 | Gets all job variables available to the task. Requires 2.104.1 agent or higher. 175 | 176 | .DESCRIPTION 177 | Gets a snapshot of the current state of all job variables available to the task. 178 | Requires a 2.104.1 agent or higher for full functionality. 179 | 180 | Returns an array of objects with the following properties: 181 | [string]Name 182 | [string]Value 183 | [bool]Secret 184 | 185 | Limitations on an agent prior to 2.104.1: 186 | 1) The return value does not include all public variables. Only public variables 187 | that have been added using setVariable are returned. 188 | 2) The name returned for each secret variable is the formatted environment variable 189 | name, not the actual variable name (unless it was set explicitly at runtime using 190 | setVariable). 191 | #> 192 | function Get-TaskVariableInfo { 193 | [CmdletBinding()] 194 | param() 195 | 196 | foreach ($info in $script:knownVariables.Values) { 197 | New-Object -TypeName psobject -Property @{ 198 | Name = $info.Name 199 | Value = Get-TaskVariable -Name $info.Name 200 | Secret = $info.Secret 201 | } 202 | } 203 | } 204 | 205 | <# 206 | .SYNOPSIS 207 | Sets a task variable. 208 | 209 | .DESCRIPTION 210 | Sets a task variable in the current task context as well as in the current job context. This allows the task variable to retrieved by subsequent tasks within the same job. 211 | #> 212 | function Set-TaskVariable { 213 | [CmdletBinding()] 214 | param( 215 | [Parameter(Mandatory = $true)] 216 | [string]$Name, 217 | [string]$Value, 218 | [switch]$Secret) 219 | 220 | # Once a secret always a secret. 221 | $variableKey = Get-VariableKey -Name $Name 222 | [bool]$Secret = $Secret -or $script:knownVariables.$variableKey.Secret 223 | if ($Secret) { 224 | $vaultKey = "SECRET_$variableKey" 225 | if (!$Value) { 226 | # Clear the secret. 227 | Write-Verbose "Set $Name = ''" 228 | $script:vault.Remove($vaultKey) 229 | } else { 230 | # Store the secret in the vault. 231 | Write-Verbose "Set $Name = '********'" 232 | $script:vault[$vaultKey] = New-Object System.Management.Automation.PSCredential( 233 | $vaultKey, 234 | (ConvertTo-SecureString -String $Value -AsPlainText -Force)) 235 | } 236 | 237 | # Clear the environment variable. 238 | Set-Item -LiteralPath "Env:$variableKey" -Value '' 239 | } else { 240 | # Set the environment variable. 241 | Write-Verbose "Set $Name = '$Value'" 242 | Set-Item -LiteralPath "Env:$variableKey" -Value $Value 243 | } 244 | 245 | # Store the metadata. 246 | $script:knownVariables[$variableKey] = New-Object -TypeName psobject -Property @{ 247 | Name = $name 248 | Secret = $Secret 249 | } 250 | 251 | # Persist the variable in the task context. 252 | Write-SetVariable -Name $Name -Value $Value -Secret:$Secret 253 | } 254 | 255 | ######################################## 256 | # Private functions. 257 | ######################################## 258 | function Get-VaultValue { 259 | [CmdletBinding(DefaultParameterSetName = 'Require')] 260 | param( 261 | [Parameter(Mandatory = $true)] 262 | [string]$Description, 263 | [Parameter(Mandatory = $true)] 264 | [string]$Key, 265 | [Parameter(ParameterSetName = 'Require')] 266 | [switch]$Require, 267 | [Parameter(ParameterSetName = 'Default')] 268 | [object]$Default, 269 | [switch]$AsBool, 270 | [switch]$AsInt) 271 | 272 | # Attempt to get the vault value. 273 | $value = $null 274 | if ($psCredential = $script:vault[$Key]) { 275 | $value = $psCredential.GetNetworkCredential().Password 276 | } elseif (!$script:nonInteractive) { 277 | # The value wasn't found. Prompt for the value if running in interactive dev mode. 278 | $value = Read-Host -Prompt $Description 279 | if ($value) { 280 | $script:vault[$Key] = New-Object System.Management.Automation.PSCredential( 281 | $Key, 282 | (ConvertTo-SecureString -String $value -AsPlainText -Force)) 283 | } 284 | } 285 | 286 | Get-Value -Value $value @PSBoundParameters 287 | } 288 | 289 | function Get-Value { 290 | [CmdletBinding(DefaultParameterSetName = 'Require')] 291 | param( 292 | [string]$Value, 293 | [Parameter(Mandatory = $true)] 294 | [string]$Description, 295 | [Parameter(Mandatory = $true)] 296 | [string]$Key, 297 | [Parameter(ParameterSetName = 'Require')] 298 | [switch]$Require, 299 | [Parameter(ParameterSetName = 'Default')] 300 | [object]$Default, 301 | [switch]$AsBool, 302 | [switch]$AsInt) 303 | 304 | $result = $Value 305 | if ($result) { 306 | if ($Key -like 'ENDPOINT_AUTH_*') { 307 | Write-Verbose "$($Key): '********'" 308 | } else { 309 | Write-Verbose "$($Key): '$result'" 310 | } 311 | } else { 312 | Write-Verbose "$Key (empty)" 313 | 314 | # Write error if required. 315 | if ($Require) { 316 | Write-Error "$(Get-LocString -Key PSLIB_Required0 $Description)" 317 | return 318 | } 319 | 320 | # Fallback to the default if provided. 321 | if ($PSCmdlet.ParameterSetName -eq 'Default') { 322 | $result = $Default 323 | $OFS = ' ' 324 | Write-Verbose " Defaulted to: '$result'" 325 | } else { 326 | $result = '' 327 | } 328 | } 329 | 330 | # Convert to bool if specified. 331 | if ($AsBool) { 332 | if ($result -isnot [bool]) { 333 | $result = "$result" -in '1', 'true' 334 | Write-Verbose " Converted to bool: $result" 335 | } 336 | 337 | return $result 338 | } 339 | 340 | # Convert to int if specified. 341 | if ($AsInt) { 342 | if ($result -isnot [int]) { 343 | try { 344 | $result = [int]"$result" 345 | } catch { 346 | $result = 0 347 | } 348 | 349 | Write-Verbose " Converted to int: $result" 350 | } 351 | 352 | return $result 353 | } 354 | 355 | return $result 356 | } 357 | 358 | function Initialize-Inputs { 359 | # Store endpoints, inputs, and secret variables in the vault. 360 | foreach ($variable in (Get-ChildItem -Path Env:ENDPOINT_?*, Env:INPUT_?*, Env:SECRET_?*)) { 361 | # Record the secret variable metadata. This is required by Get-TaskVariable to 362 | # retrieve the value. In a 2.104.1 agent or higher, this metadata will be overwritten 363 | # when $env:VSTS_SECRET_VARIABLES is processed. 364 | if ($variable.Name -like 'SECRET_?*') { 365 | $variableKey = $variable.Name.Substring('SECRET_'.Length) 366 | $script:knownVariables[$variableKey] = New-Object -TypeName psobject -Property @{ 367 | # This is technically not the variable name (has underscores instead of dots), 368 | # but it's good enough to make Get-TaskVariable work in a pre-2.104.1 agent 369 | # where $env:VSTS_SECRET_VARIABLES is not defined. 370 | Name = $variableKey 371 | Secret = $true 372 | } 373 | } 374 | 375 | # Store the value in the vault. 376 | $vaultKey = $variable.Name 377 | if ($variable.Value) { 378 | $script:vault[$vaultKey] = New-Object System.Management.Automation.PSCredential( 379 | $vaultKey, 380 | (ConvertTo-SecureString -String $variable.Value -AsPlainText -Force)) 381 | } 382 | 383 | # Clear the environment variable. 384 | Remove-Item -LiteralPath "Env:$($variable.Name)" 385 | } 386 | 387 | # Record the public variable names. Env var added in 2.104.1 agent. 388 | if ($env:VSTS_PUBLIC_VARIABLES) { 389 | foreach ($name in (ConvertFrom-Json -InputObject $env:VSTS_PUBLIC_VARIABLES)) { 390 | $variableKey = Get-VariableKey -Name $name 391 | $script:knownVariables[$variableKey] = New-Object -TypeName psobject -Property @{ 392 | Name = $name 393 | Secret = $false 394 | } 395 | } 396 | 397 | $env:VSTS_PUBLIC_VARIABLES = '' 398 | } 399 | 400 | # Record the secret variable names. Env var added in 2.104.1 agent. 401 | if ($env:VSTS_SECRET_VARIABLES) { 402 | foreach ($name in (ConvertFrom-Json -InputObject $env:VSTS_SECRET_VARIABLES)) { 403 | $variableKey = Get-VariableKey -Name $name 404 | $script:knownVariables[$variableKey] = New-Object -TypeName psobject -Property @{ 405 | Name = $name 406 | Secret = $true 407 | } 408 | } 409 | 410 | $env:VSTS_SECRET_VARIABLES = '' 411 | } 412 | } 413 | 414 | function Get-VariableKey { 415 | [CmdletBinding()] 416 | param( 417 | [Parameter(Mandatory = $true)] 418 | [string]$Name) 419 | 420 | if ($Name -ne 'agent.jobstatus') { 421 | $Name = $Name.Replace('.', '_') 422 | } 423 | 424 | $Name.ToUpperInvariant() 425 | } 426 | -------------------------------------------------------------------------------- /variablerehydration-task/v0/ps_modules/VstsTaskSdk/LocalizationFunctions.ps1: -------------------------------------------------------------------------------- 1 | $script:resourceStrings = @{ } 2 | 3 | <# 4 | .SYNOPSIS 5 | Gets a localized resource string. 6 | 7 | .DESCRIPTION 8 | Gets a localized resource string and optionally formats the string with arguments. 9 | 10 | If the format fails (due to a bad format string or incorrect expected arguments in the format string), then the format string is returned followed by each of the arguments (delimited by a space). 11 | 12 | If the lookup key is not found, then the lookup key is returned followed by each of the arguments (delimited by a space). 13 | 14 | .PARAMETER Require 15 | Writes an error to the error pipeline if the endpoint is not found. 16 | #> 17 | function Get-LocString { 18 | [CmdletBinding()] 19 | param( 20 | [Parameter(Mandatory = $true, Position = 1)] 21 | [string]$Key, 22 | [Parameter(Position = 2)] 23 | [object[]]$ArgumentList = @( )) 24 | 25 | # Due to the dynamically typed nature of PowerShell, a single null argument passed 26 | # to an array parameter is interpreted as a null array. 27 | if ([object]::ReferenceEquals($null, $ArgumentList)) { 28 | $ArgumentList = @( $null ) 29 | } 30 | 31 | # Lookup the format string. 32 | $format = '' 33 | if (!($format = $script:resourceStrings[$Key])) { 34 | # Warn the key was not found. Prevent recursion if the lookup key is the 35 | # "string resource key not found" lookup key. 36 | $resourceNotFoundKey = 'PSLIB_StringResourceKeyNotFound0' 37 | if ($key -ne $resourceNotFoundKey) { 38 | Write-Warning (Get-LocString -Key $resourceNotFoundKey -ArgumentList $Key) 39 | } 40 | 41 | # Fallback to just the key itself if there aren't any arguments to format. 42 | if (!$ArgumentList.Count) { return $key } 43 | 44 | # Otherwise fallback to the key followed by the arguments. 45 | $OFS = " " 46 | return "$key $ArgumentList" 47 | } 48 | 49 | # Return the string if there aren't any arguments to format. 50 | if (!$ArgumentList.Count) { return $format } 51 | 52 | try { 53 | [string]::Format($format, $ArgumentList) 54 | } catch { 55 | Write-Warning (Get-LocString -Key 'PSLIB_StringFormatFailed') 56 | $OFS = " " 57 | "$format $ArgumentList" 58 | } 59 | } 60 | 61 | <# 62 | .SYNOPSIS 63 | Imports resource strings for use with Get-VstsLocString. 64 | 65 | .DESCRIPTION 66 | Imports resource strings for use with Get-VstsLocString. The imported strings are stored in an internal resource string dictionary. Optionally, if a separate resource file for the current culture exists, then the localized strings from that file then imported (overlaid) into the same internal resource string dictionary. 67 | 68 | Resource strings from the SDK are prefixed with "PSLIB_". This prefix should be avoided for custom resource strings. 69 | 70 | .Parameter LiteralPath 71 | JSON file containing resource strings. 72 | 73 | .EXAMPLE 74 | Import-VstsLocStrings -LiteralPath $PSScriptRoot\Task.json 75 | 76 | Imports strings from messages section in the JSON file. If a messages section is not defined, then no strings are imported. Example messages section: 77 | { 78 | "messages": { 79 | "Hello": "Hello you!", 80 | "Hello0": "Hello {0}!" 81 | } 82 | } 83 | 84 | .EXAMPLE 85 | Import-VstsLocStrings -LiteralPath $PSScriptRoot\Task.json 86 | 87 | Overlays strings from an optional separate resource file for the current culture. 88 | 89 | Given the task variable System.Culture is set to 'de-DE'. This variable is set by the agent based on the current culture for the job. 90 | Given the file Task.json contains: 91 | { 92 | "messages": { 93 | "GoodDay": "Good day!", 94 | } 95 | } 96 | Given the file resources.resjson\de-DE\resources.resjson: 97 | { 98 | "loc.messages.GoodDay": "Guten Tag!" 99 | } 100 | 101 | The net result from the import command would be one new key-value pair added to the internal dictionary: Key = 'GoodDay', Value = 'Guten Tag!' 102 | #> 103 | function Import-LocStrings { 104 | [CmdletBinding()] 105 | param( 106 | [Parameter(Mandatory = $true)] 107 | [string]$LiteralPath) 108 | 109 | # Validate the file exists. 110 | if (!(Test-Path -LiteralPath $LiteralPath -PathType Leaf)) { 111 | Write-Warning (Get-LocString -Key PSLIB_FileNotFound0 -ArgumentList $LiteralPath) 112 | return 113 | } 114 | 115 | # Load the json. 116 | Write-Verbose "Loading resource strings from: $LiteralPath" 117 | $count = 0 118 | if ($messages = (Get-Content -LiteralPath $LiteralPath -Encoding UTF8 | Out-String | ConvertFrom-Json).messages) { 119 | # Add each resource string to the hashtable. 120 | foreach ($member in (Get-Member -InputObject $messages -MemberType NoteProperty)) { 121 | [string]$key = $member.Name 122 | $script:resourceStrings[$key] = $messages."$key" 123 | $count++ 124 | } 125 | } 126 | 127 | Write-Verbose "Loaded $count strings." 128 | 129 | # Get the culture. 130 | $culture = Get-TaskVariable -Name "System.Culture" -Default "en-US" 131 | 132 | # Load the resjson. 133 | $resjsonPath = "$([System.IO.Path]::GetDirectoryName($LiteralPath))\Strings\resources.resjson\$culture\resources.resjson" 134 | if (Test-Path -LiteralPath $resjsonPath) { 135 | Write-Verbose "Loading resource strings from: $resjsonPath" 136 | $count = 0 137 | $resjson = Get-Content -LiteralPath $resjsonPath -Encoding UTF8 | Out-String | ConvertFrom-Json 138 | foreach ($member in (Get-Member -Name loc.messages.* -InputObject $resjson -MemberType NoteProperty)) { 139 | if (!($value = $resjson."$($member.Name)")) { 140 | continue 141 | } 142 | 143 | [string]$key = $member.Name.Substring('loc.messages.'.Length) 144 | $script:resourceStrings[$key] = $value 145 | $count++ 146 | } 147 | 148 | Write-Verbose "Loaded $count strings." 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /variablerehydration-task/v0/ps_modules/VstsTaskSdk/LoggingCommandFunctions.ps1: -------------------------------------------------------------------------------- 1 | $script:loggingCommandPrefix = '##vso[' 2 | $script:loggingCommandEscapeMappings = @( # TODO: WHAT ABOUT "="? WHAT ABOUT "%"? 3 | New-Object psobject -Property @{ Token = ';' ; Replacement = '%3B' } 4 | New-Object psobject -Property @{ Token = "`r" ; Replacement = '%0D' } 5 | New-Object psobject -Property @{ Token = "`n" ; Replacement = '%0A' } 6 | ) 7 | # TODO: BUG: Escape ] 8 | # TODO: BUG: Escape % ??? 9 | # TODO: Add test to verify don't need to escape "=". 10 | 11 | <# 12 | .SYNOPSIS 13 | See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md 14 | 15 | .PARAMETER AsOutput 16 | Indicates whether to write the logging command directly to the host or to the output pipeline. 17 | #> 18 | function Write-AddAttachment { 19 | [CmdletBinding()] 20 | param( 21 | [Parameter(Mandatory = $true)] 22 | [string]$Type, 23 | [Parameter(Mandatory = $true)] 24 | [string]$Name, 25 | [Parameter(Mandatory = $true)] 26 | [string]$Path, 27 | [switch]$AsOutput) 28 | 29 | Write-LoggingCommand -Area 'task' -Event 'addattachment' -Data $Path -Properties @{ 30 | 'type' = $Type 31 | 'name' = $Name 32 | } -AsOutput:$AsOutput 33 | } 34 | 35 | <# 36 | .SYNOPSIS 37 | See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md 38 | 39 | .PARAMETER AsOutput 40 | Indicates whether to write the logging command directly to the host or to the output pipeline. 41 | #> 42 | function Write-AddBuildTag { 43 | [CmdletBinding()] 44 | param( 45 | [Parameter(Mandatory = $true)] 46 | [string]$Value, 47 | [switch]$AsOutput) 48 | 49 | Write-LoggingCommand -Area 'build' -Event 'addbuildtag' -Data $Value -AsOutput:$AsOutput 50 | } 51 | 52 | <# 53 | .SYNOPSIS 54 | See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md 55 | 56 | .PARAMETER AsOutput 57 | Indicates whether to write the logging command directly to the host or to the output pipeline. 58 | #> 59 | function Write-AssociateArtifact { 60 | [CmdletBinding()] 61 | param( 62 | [Parameter(Mandatory = $true)] 63 | [string]$Name, 64 | [Parameter(Mandatory = $true)] 65 | [string]$Path, 66 | [Parameter(Mandatory = $true)] 67 | [string]$Type, 68 | [hashtable]$Properties, 69 | [switch]$AsOutput) 70 | 71 | $p = @{ } 72 | if ($Properties) { 73 | foreach ($key in $Properties.Keys) { 74 | $p[$key] = $Properties[$key] 75 | } 76 | } 77 | 78 | $p['artifactname'] = $Name 79 | $p['artifacttype'] = $Type 80 | Write-LoggingCommand -Area 'artifact' -Event 'associate' -Data $Path -Properties $p -AsOutput:$AsOutput 81 | } 82 | 83 | <# 84 | .SYNOPSIS 85 | See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md 86 | 87 | .PARAMETER AsOutput 88 | Indicates whether to write the logging command directly to the host or to the output pipeline. 89 | #> 90 | function Write-LogDetail { 91 | [CmdletBinding()] 92 | param( 93 | [Parameter(Mandatory = $true)] 94 | [guid]$Id, 95 | $ParentId, 96 | [string]$Type, 97 | [string]$Name, 98 | $Order, 99 | $StartTime, 100 | $FinishTime, 101 | $Progress, 102 | [ValidateSet('Unknown', 'Initialized', 'InProgress', 'Completed')] 103 | [Parameter()] 104 | $State, 105 | [ValidateSet('Succeeded', 'SucceededWithIssues', 'Failed', 'Cancelled', 'Skipped')] 106 | [Parameter()] 107 | $Result, 108 | [string]$Message, 109 | [switch]$AsOutput) 110 | 111 | Write-LoggingCommand -Area 'task' -Event 'logdetail' -Data $Message -Properties @{ 112 | 'id' = $Id 113 | 'parentid' = $ParentId 114 | 'type' = $Type 115 | 'name' = $Name 116 | 'order' = $Order 117 | 'starttime' = $StartTime 118 | 'finishtime' = $FinishTime 119 | 'progress' = $Progress 120 | 'state' = $State 121 | 'result' = $Result 122 | } -AsOutput:$AsOutput 123 | } 124 | 125 | <# 126 | .SYNOPSIS 127 | See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md 128 | 129 | .PARAMETER AsOutput 130 | Indicates whether to write the logging command directly to the host or to the output pipeline. 131 | #> 132 | function Write-SetProgress { 133 | [CmdletBinding()] 134 | param( 135 | [ValidateRange(0, 100)] 136 | [Parameter(Mandatory = $true)] 137 | [int]$Percent, 138 | [string]$CurrentOperation, 139 | [switch]$AsOutput) 140 | 141 | Write-LoggingCommand -Area 'task' -Event 'setprogress' -Data $CurrentOperation -Properties @{ 142 | 'value' = $Percent 143 | } -AsOutput:$AsOutput 144 | } 145 | 146 | <# 147 | .SYNOPSIS 148 | See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md 149 | 150 | .PARAMETER AsOutput 151 | Indicates whether to write the logging command directly to the host or to the output pipeline. 152 | #> 153 | function Write-SetResult { 154 | [CmdletBinding(DefaultParameterSetName = 'AsOutput')] 155 | param( 156 | [ValidateSet("Succeeded", "SucceededWithIssues", "Failed", "Cancelled", "Skipped")] 157 | [Parameter(Mandatory = $true)] 158 | [string]$Result, 159 | [string]$Message, 160 | [Parameter(ParameterSetName = 'AsOutput')] 161 | [switch]$AsOutput, 162 | [Parameter(ParameterSetName = 'DoNotThrow')] 163 | [switch]$DoNotThrow) 164 | 165 | Write-LoggingCommand -Area 'task' -Event 'complete' -Data $Message -Properties @{ 166 | 'result' = $Result 167 | } -AsOutput:$AsOutput 168 | if ($Result -eq 'Failed' -and !$AsOutput -and !$DoNotThrow) { 169 | # Special internal exception type to control the flow. Not currently intended 170 | # for public usage and subject to change. 171 | throw (New-Object VstsTaskSdk.TerminationException($Message)) 172 | } 173 | } 174 | 175 | <# 176 | .SYNOPSIS 177 | See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md 178 | 179 | .PARAMETER AsOutput 180 | Indicates whether to write the logging command directly to the host or to the output pipeline. 181 | #> 182 | function Write-SetSecret { 183 | [CmdletBinding()] 184 | param( 185 | [Parameter(Mandatory = $true)] 186 | [string]$Value, 187 | [switch]$AsOutput) 188 | 189 | Write-LoggingCommand -Area 'task' -Event 'setsecret' -Data $Value -AsOutput:$AsOutput 190 | } 191 | 192 | <# 193 | .SYNOPSIS 194 | See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md 195 | 196 | .PARAMETER AsOutput 197 | Indicates whether to write the logging command directly to the host or to the output pipeline. 198 | #> 199 | function Write-SetVariable { 200 | [CmdletBinding()] 201 | param( 202 | [Parameter(Mandatory = $true)] 203 | [string]$Name, 204 | [string]$Value, 205 | [switch]$Secret, 206 | [switch]$AsOutput) 207 | 208 | Write-LoggingCommand -Area 'task' -Event 'setvariable' -Data $Value -Properties @{ 209 | 'variable' = $Name 210 | 'issecret' = $Secret 211 | } -AsOutput:$AsOutput 212 | } 213 | 214 | <# 215 | .SYNOPSIS 216 | See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md 217 | 218 | .PARAMETER AsOutput 219 | Indicates whether to write the logging command directly to the host or to the output pipeline. 220 | #> 221 | function Write-TaskDebug { 222 | [CmdletBinding()] 223 | param( 224 | [string]$Message, 225 | [switch]$AsOutput) 226 | 227 | Write-TaskDebug_Internal @PSBoundParameters 228 | } 229 | 230 | <# 231 | .SYNOPSIS 232 | See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md 233 | 234 | .PARAMETER AsOutput 235 | Indicates whether to write the logging command directly to the host or to the output pipeline. 236 | #> 237 | function Write-TaskError { 238 | [CmdletBinding()] 239 | param( 240 | [string]$Message, 241 | [string]$ErrCode, 242 | [string]$SourcePath, 243 | [string]$LineNumber, 244 | [string]$ColumnNumber, 245 | [switch]$AsOutput) 246 | 247 | Write-LogIssue -Type error @PSBoundParameters 248 | } 249 | 250 | <# 251 | .SYNOPSIS 252 | See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md 253 | 254 | .PARAMETER AsOutput 255 | Indicates whether to write the logging command directly to the host or to the output pipeline. 256 | #> 257 | function Write-TaskVerbose { 258 | [CmdletBinding()] 259 | param( 260 | [string]$Message, 261 | [switch]$AsOutput) 262 | 263 | Write-TaskDebug_Internal @PSBoundParameters -AsVerbose 264 | } 265 | 266 | <# 267 | .SYNOPSIS 268 | See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md 269 | 270 | .PARAMETER AsOutput 271 | Indicates whether to write the logging command directly to the host or to the output pipeline. 272 | #> 273 | function Write-TaskWarning { 274 | [CmdletBinding()] 275 | param( 276 | [string]$Message, 277 | [string]$ErrCode, 278 | [string]$SourcePath, 279 | [string]$LineNumber, 280 | [string]$ColumnNumber, 281 | [switch]$AsOutput) 282 | 283 | Write-LogIssue -Type warning @PSBoundParameters 284 | } 285 | 286 | <# 287 | .SYNOPSIS 288 | See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md 289 | 290 | .PARAMETER AsOutput 291 | Indicates whether to write the logging command directly to the host or to the output pipeline. 292 | #> 293 | function Write-UpdateBuildNumber { 294 | [CmdletBinding()] 295 | param( 296 | [Parameter(Mandatory = $true)] 297 | [string]$Value, 298 | [switch]$AsOutput) 299 | 300 | Write-LoggingCommand -Area 'build' -Event 'updatebuildnumber' -Data $Value -AsOutput:$AsOutput 301 | } 302 | 303 | <# 304 | .SYNOPSIS 305 | See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md 306 | 307 | .PARAMETER AsOutput 308 | Indicates whether to write the logging command directly to the host or to the output pipeline. 309 | #> 310 | function Write-UploadArtifact { 311 | [CmdletBinding()] 312 | param( 313 | [Parameter(Mandatory = $true)] 314 | [string]$ContainerFolder, 315 | [Parameter(Mandatory = $true)] 316 | [string]$Name, 317 | [Parameter(Mandatory = $true)] 318 | [string]$Path, 319 | [switch]$AsOutput) 320 | 321 | Write-LoggingCommand -Area 'artifact' -Event 'upload' -Data $Path -Properties @{ 322 | 'containerfolder' = $ContainerFolder 323 | 'artifactname' = $Name 324 | } -AsOutput:$AsOutput 325 | } 326 | 327 | <# 328 | .SYNOPSIS 329 | See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md 330 | 331 | .PARAMETER AsOutput 332 | Indicates whether to write the logging command directly to the host or to the output pipeline. 333 | #> 334 | function Write-UploadBuildLog { 335 | [CmdletBinding()] 336 | param( 337 | [Parameter(Mandatory = $true)] 338 | [string]$Path, 339 | [switch]$AsOutput) 340 | 341 | Write-LoggingCommand -Area 'build' -Event 'uploadlog' -Data $Path -AsOutput:$AsOutput 342 | } 343 | 344 | ######################################## 345 | # Private functions. 346 | ######################################## 347 | function Format-LoggingCommandData { 348 | [CmdletBinding()] 349 | param([string]$Value, [switch]$Reverse) 350 | 351 | if (!$Value) { 352 | return '' 353 | } 354 | 355 | if (!$Reverse) { 356 | foreach ($mapping in $script:loggingCommandEscapeMappings) { 357 | $Value = $Value.Replace($mapping.Token, $mapping.Replacement) 358 | } 359 | } else { 360 | for ($i = $script:loggingCommandEscapeMappings.Length - 1 ; $i -ge 0 ; $i--) { 361 | $mapping = $script:loggingCommandEscapeMappings[$i] 362 | $Value = $Value.Replace($mapping.Replacement, $mapping.Token) 363 | } 364 | } 365 | 366 | return $Value 367 | } 368 | 369 | function Format-LoggingCommand { 370 | [CmdletBinding()] 371 | param( 372 | [Parameter(Mandatory = $true)] 373 | [string]$Area, 374 | [Parameter(Mandatory = $true)] 375 | [string]$Event, 376 | [string]$Data, 377 | [hashtable]$Properties) 378 | 379 | # Append the preamble. 380 | [System.Text.StringBuilder]$sb = New-Object -TypeName System.Text.StringBuilder 381 | $null = $sb.Append($script:loggingCommandPrefix).Append($Area).Append('.').Append($Event) 382 | 383 | # Append the properties. 384 | if ($Properties) { 385 | $first = $true 386 | foreach ($key in $Properties.Keys) { 387 | [string]$value = Format-LoggingCommandData $Properties[$key] 388 | if ($value) { 389 | if ($first) { 390 | $null = $sb.Append(' ') 391 | $first = $false 392 | } else { 393 | $null = $sb.Append(';') 394 | } 395 | 396 | $null = $sb.Append("$key=$value") 397 | } 398 | } 399 | } 400 | 401 | # Append the tail and output the value. 402 | $Data = Format-LoggingCommandData $Data 403 | $sb.Append(']').Append($Data).ToString() 404 | } 405 | 406 | function Write-LoggingCommand { 407 | [CmdletBinding(DefaultParameterSetName = 'Parameters')] 408 | param( 409 | [Parameter(Mandatory = $true, ParameterSetName = 'Parameters')] 410 | [string]$Area, 411 | [Parameter(Mandatory = $true, ParameterSetName = 'Parameters')] 412 | [string]$Event, 413 | [Parameter(ParameterSetName = 'Parameters')] 414 | [string]$Data, 415 | [Parameter(ParameterSetName = 'Parameters')] 416 | [hashtable]$Properties, 417 | [Parameter(Mandatory = $true, ParameterSetName = 'Object')] 418 | $Command, 419 | [switch]$AsOutput) 420 | 421 | if ($PSCmdlet.ParameterSetName -eq 'Object') { 422 | Write-LoggingCommand -Area $Command.Area -Event $Command.Event -Data $Command.Data -Properties $Command.Properties -AsOutput:$AsOutput 423 | return 424 | } 425 | 426 | $command = Format-LoggingCommand -Area $Area -Event $Event -Data $Data -Properties $Properties 427 | if ($AsOutput) { 428 | $command 429 | } else { 430 | Write-Host $command 431 | } 432 | } 433 | 434 | function Write-LogIssue { 435 | [CmdletBinding()] 436 | param( 437 | [ValidateSet('warning', 'error')] 438 | [Parameter(Mandatory = $true)] 439 | [string]$Type, 440 | [string]$Message, 441 | [string]$ErrCode, 442 | [string]$SourcePath, 443 | [string]$LineNumber, 444 | [string]$ColumnNumber, 445 | [switch]$AsOutput) 446 | 447 | $command = Format-LoggingCommand -Area 'task' -Event 'logissue' -Data $Message -Properties @{ 448 | 'type' = $Type 449 | 'code' = $ErrCode 450 | 'sourcepath' = $SourcePath 451 | 'linenumber' = $LineNumber 452 | 'columnnumber' = $ColumnNumber 453 | } 454 | if ($AsOutput) { 455 | return $command 456 | } 457 | 458 | if ($Type -eq 'error') { 459 | $foregroundColor = $host.PrivateData.ErrorForegroundColor 460 | $backgroundColor = $host.PrivateData.ErrorBackgroundColor 461 | if ($foregroundColor -isnot [System.ConsoleColor] -or $backgroundColor -isnot [System.ConsoleColor]) { 462 | $foregroundColor = [System.ConsoleColor]::Red 463 | $backgroundColor = [System.ConsoleColor]::Black 464 | } 465 | } else { 466 | $foregroundColor = $host.PrivateData.WarningForegroundColor 467 | $backgroundColor = $host.PrivateData.WarningBackgroundColor 468 | if ($foregroundColor -isnot [System.ConsoleColor] -or $backgroundColor -isnot [System.ConsoleColor]) { 469 | $foregroundColor = [System.ConsoleColor]::Yellow 470 | $backgroundColor = [System.ConsoleColor]::Black 471 | } 472 | } 473 | 474 | Write-Host $command -ForegroundColor $foregroundColor -BackgroundColor $backgroundColor 475 | } 476 | 477 | function Write-TaskDebug_Internal { 478 | [CmdletBinding()] 479 | param( 480 | [string]$Message, 481 | [switch]$AsVerbose, 482 | [switch]$AsOutput) 483 | 484 | $command = Format-LoggingCommand -Area 'task' -Event 'debug' -Data $Message 485 | if ($AsOutput) { 486 | return $command 487 | } 488 | 489 | if ($AsVerbose) { 490 | $foregroundColor = $host.PrivateData.VerboseForegroundColor 491 | $backgroundColor = $host.PrivateData.VerboseBackgroundColor 492 | if ($foregroundColor -isnot [System.ConsoleColor] -or $backgroundColor -isnot [System.ConsoleColor]) { 493 | $foregroundColor = [System.ConsoleColor]::Cyan 494 | $backgroundColor = [System.ConsoleColor]::Black 495 | } 496 | } else { 497 | $foregroundColor = $host.PrivateData.DebugForegroundColor 498 | $backgroundColor = $host.PrivateData.DebugBackgroundColor 499 | if ($foregroundColor -isnot [System.ConsoleColor] -or $backgroundColor -isnot [System.ConsoleColor]) { 500 | $foregroundColor = [System.ConsoleColor]::DarkGray 501 | $backgroundColor = [System.ConsoleColor]::Black 502 | } 503 | } 504 | 505 | Write-Host -Object $command -ForegroundColor $foregroundColor -BackgroundColor $backgroundColor 506 | } 507 | -------------------------------------------------------------------------------- /variablerehydration-task/v0/ps_modules/VstsTaskSdk/LongPathFunctions.ps1: -------------------------------------------------------------------------------- 1 | ######################################## 2 | # Private functions. 3 | ######################################## 4 | function ConvertFrom-LongFormPath { 5 | [CmdletBinding()] 6 | param([string]$Path) 7 | 8 | if ($Path) { 9 | if ($Path.StartsWith('\\?\UNC')) { 10 | # E.g. \\?\UNC\server\share -> \\server\share 11 | return $Path.Substring(1, '\?\UNC'.Length) 12 | } elseif ($Path.StartsWith('\\?\')) { 13 | # E.g. \\?\C:\directory -> C:\directory 14 | return $Path.Substring('\\?\'.Length) 15 | } 16 | } 17 | 18 | return $Path 19 | } 20 | function ConvertTo-LongFormPath { 21 | [CmdletBinding()] 22 | param( 23 | [Parameter(Mandatory = $true)] 24 | [string]$Path) 25 | 26 | [string]$longFormPath = Get-FullNormalizedPath -Path $Path 27 | if ($longFormPath -and !$longFormPath.StartsWith('\\?')) { 28 | if ($longFormPath.StartsWith('\\')) { 29 | # E.g. \\server\share -> \\?\UNC\server\share 30 | return "\\?\UNC$($longFormPath.Substring(1))" 31 | } else { 32 | # E.g. C:\directory -> \\?\C:\directory 33 | return "\\?\$longFormPath" 34 | } 35 | } 36 | 37 | return $longFormPath 38 | } 39 | 40 | # TODO: ADD A SWITCH TO EXCLUDE FILES, A SWITCH TO EXCLUDE DIRECTORIES, AND A SWITCH NOT TO FOLLOW REPARSE POINTS. 41 | function Get-DirectoryChildItem { 42 | [CmdletBinding()] 43 | param( 44 | [string]$Path, 45 | [ValidateNotNullOrEmpty()] 46 | [Parameter()] 47 | [string]$Filter = "*", 48 | [switch]$Force, 49 | [VstsTaskSdk.FS.FindFlags]$Flags = [VstsTaskSdk.FS.FindFlags]::LargeFetch, 50 | [VstsTaskSdk.FS.FindInfoLevel]$InfoLevel = [VstsTaskSdk.FS.FindInfoLevel]::Basic, 51 | [switch]$Recurse) 52 | 53 | $stackOfDirectoryQueues = New-Object System.Collections.Stack 54 | while ($true) { 55 | $directoryQueue = New-Object System.Collections.Queue 56 | $fileQueue = New-Object System.Collections.Queue 57 | $findData = New-Object VstsTaskSdk.FS.FindData 58 | $longFormPath = (ConvertTo-LongFormPath $Path) 59 | $handle = $null 60 | try { 61 | $handle = [VstsTaskSdk.FS.NativeMethods]::FindFirstFileEx( 62 | [System.IO.Path]::Combine($longFormPath, $Filter), 63 | $InfoLevel, 64 | $findData, 65 | [VstsTaskSdk.FS.FindSearchOps]::NameMatch, 66 | [System.IntPtr]::Zero, 67 | $Flags) 68 | if (!$handle.IsInvalid) { 69 | while ($true) { 70 | if ($findData.fileName -notin '.', '..') { 71 | $attributes = [VstsTaskSdk.FS.Attributes]$findData.fileAttributes 72 | # If the item is hidden, check if $Force is specified. 73 | if ($Force -or !$attributes.HasFlag([VstsTaskSdk.FS.Attributes]::Hidden)) { 74 | # Create the item. 75 | $item = New-Object -TypeName psobject -Property @{ 76 | 'Attributes' = $attributes 77 | 'FullName' = (ConvertFrom-LongFormPath -Path ([System.IO.Path]::Combine($Path, $findData.fileName))) 78 | 'Name' = $findData.fileName 79 | } 80 | # Output directories immediately. 81 | if ($item.Attributes.HasFlag([VstsTaskSdk.FS.Attributes]::Directory)) { 82 | $item 83 | # Append to the directory queue if recursive and default filter. 84 | if ($Recurse -and $Filter -eq '*') { 85 | $directoryQueue.Enqueue($item) 86 | } 87 | } else { 88 | # Hold the files until all directories have been output. 89 | $fileQueue.Enqueue($item) 90 | } 91 | } 92 | } 93 | 94 | if (!([VstsTaskSdk.FS.NativeMethods]::FindNextFile($handle, $findData))) { break } 95 | 96 | if ($handle.IsInvalid) { 97 | throw (New-Object -TypeName System.ComponentModel.Win32Exception -ArgumentList @( 98 | [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() 99 | Get-LocString -Key PSLIB_EnumeratingSubdirectoriesFailedForPath0 -ArgumentList $Path 100 | )) 101 | } 102 | } 103 | } 104 | } finally { 105 | if ($handle -ne $null) { $handle.Dispose() } 106 | } 107 | 108 | # If recursive and non-default filter, queue child directories. 109 | if ($Recurse -and $Filter -ne '*') { 110 | $findData = New-Object VstsTaskSdk.FS.FindData 111 | $handle = $null 112 | try { 113 | $handle = [VstsTaskSdk.FS.NativeMethods]::FindFirstFileEx( 114 | [System.IO.Path]::Combine($longFormPath, '*'), 115 | [VstsTaskSdk.FS.FindInfoLevel]::Basic, 116 | $findData, 117 | [VstsTaskSdk.FS.FindSearchOps]::NameMatch, 118 | [System.IntPtr]::Zero, 119 | $Flags) 120 | if (!$handle.IsInvalid) { 121 | while ($true) { 122 | if ($findData.fileName -notin '.', '..') { 123 | $attributes = [VstsTaskSdk.FS.Attributes]$findData.fileAttributes 124 | # If the item is hidden, check if $Force is specified. 125 | if ($Force -or !$attributes.HasFlag([VstsTaskSdk.FS.Attributes]::Hidden)) { 126 | # Collect directories only. 127 | if ($attributes.HasFlag([VstsTaskSdk.FS.Attributes]::Directory)) { 128 | # Create the item. 129 | $item = New-Object -TypeName psobject -Property @{ 130 | 'Attributes' = $attributes 131 | 'FullName' = (ConvertFrom-LongFormPath -Path ([System.IO.Path]::Combine($Path, $findData.fileName))) 132 | 'Name' = $findData.fileName 133 | } 134 | $directoryQueue.Enqueue($item) 135 | } 136 | } 137 | } 138 | 139 | if (!([VstsTaskSdk.FS.NativeMethods]::FindNextFile($handle, $findData))) { break } 140 | 141 | if ($handle.IsInvalid) { 142 | throw (New-Object -TypeName System.ComponentModel.Win32Exception -ArgumentList @( 143 | [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() 144 | Get-LocString -Key PSLIB_EnumeratingSubdirectoriesFailedForPath0 -ArgumentList $Path 145 | )) 146 | } 147 | } 148 | } 149 | } finally { 150 | if ($handle -ne $null) { $handle.Dispose() } 151 | } 152 | } 153 | 154 | # Output the files. 155 | $fileQueue 156 | 157 | # Push the directory queue onto the stack if any directories were found. 158 | if ($directoryQueue.Count) { $stackOfDirectoryQueues.Push($directoryQueue) } 159 | 160 | # Break out of the loop if no more directory queues to process. 161 | if (!$stackOfDirectoryQueues.Count) { break } 162 | 163 | # Get the next path. 164 | $directoryQueue = $stackOfDirectoryQueues.Peek() 165 | $Path = $directoryQueue.Dequeue().FullName 166 | 167 | # Pop the directory queue if it's empty. 168 | if (!$directoryQueue.Count) { $null = $stackOfDirectoryQueues.Pop() } 169 | } 170 | } 171 | 172 | function Get-FullNormalizedPath { 173 | [CmdletBinding()] 174 | param( 175 | [Parameter(Mandatory = $true)] 176 | [string]$Path) 177 | 178 | [string]$outPath = $Path 179 | [uint32]$bufferSize = [VstsTaskSdk.FS.NativeMethods]::GetFullPathName($Path, 0, $null, $null) 180 | [int]$lastWin32Error = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() 181 | if ($bufferSize -gt 0) { 182 | $absolutePath = New-Object System.Text.StringBuilder([int]$bufferSize) 183 | [uint32]$length = [VstsTaskSdk.FS.NativeMethods]::GetFullPathName($Path, $bufferSize, $absolutePath, $null) 184 | $lastWin32Error = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() 185 | if ($length -gt 0) { 186 | $outPath = $absolutePath.ToString() 187 | } else { 188 | throw (New-Object -TypeName System.ComponentModel.Win32Exception -ArgumentList @( 189 | $lastWin32Error 190 | Get-LocString -Key PSLIB_PathLengthNotReturnedFor0 -ArgumentList $Path 191 | )) 192 | } 193 | } else { 194 | throw (New-Object -TypeName System.ComponentModel.Win32Exception -ArgumentList @( 195 | $lastWin32Error 196 | Get-LocString -Key PSLIB_PathLengthNotReturnedFor0 -ArgumentList $Path 197 | )) 198 | } 199 | 200 | if ($outPath.EndsWith('\') -and !$outPath.EndsWith(':\')) { 201 | $outPath = $outPath.TrimEnd('\') 202 | } 203 | 204 | $outPath 205 | } 206 | 207 | ######################################## 208 | # Types. 209 | ######################################## 210 | # If the type has already been loaded once, then it is not loaded again. 211 | Write-Verbose "Adding long path native methods." 212 | Add-Type -Debug:$false -TypeDefinition @' 213 | namespace VstsTaskSdk.FS 214 | { 215 | using System; 216 | using System.Runtime.InteropServices; 217 | 218 | public static class NativeMethods 219 | { 220 | private const string Kernel32Dll = "kernel32.dll"; 221 | 222 | [DllImport(Kernel32Dll, CharSet = CharSet.Unicode, BestFitMapping = false, ThrowOnUnmappableChar = true)] 223 | [return: MarshalAs(UnmanagedType.Bool)] 224 | public static extern bool FindClose(IntPtr hFindFile); 225 | 226 | // HANDLE WINAPI FindFirstFile( 227 | // _In_ LPCTSTR lpFileName, 228 | // _Out_ LPWIN32_FIND_DATA lpFindFileData 229 | // ); 230 | [DllImport(Kernel32Dll, CharSet = CharSet.Unicode, BestFitMapping = false, ThrowOnUnmappableChar = true, SetLastError = true)] 231 | public static extern SafeFindHandle FindFirstFile( 232 | [MarshalAs(UnmanagedType.LPTStr)] 233 | string fileName, 234 | [In, Out] FindData findFileData 235 | ); 236 | 237 | //HANDLE WINAPI FindFirstFileEx( 238 | // _In_ LPCTSTR lpFileName, 239 | // _In_ FINDEX_INFO_LEVELS fInfoLevelId, 240 | // _Out_ LPVOID lpFindFileData, 241 | // _In_ FINDEX_SEARCH_OPS fSearchOp, 242 | // _Reserved_ LPVOID lpSearchFilter, 243 | // _In_ DWORD dwAdditionalFlags 244 | //); 245 | [DllImport(Kernel32Dll, CharSet = CharSet.Unicode, BestFitMapping = false, ThrowOnUnmappableChar = true, SetLastError = true)] 246 | public static extern SafeFindHandle FindFirstFileEx( 247 | [MarshalAs(UnmanagedType.LPTStr)] 248 | string fileName, 249 | [In] FindInfoLevel fInfoLevelId, 250 | [In, Out] FindData lpFindFileData, 251 | [In] FindSearchOps fSearchOp, 252 | IntPtr lpSearchFilter, 253 | [In] FindFlags dwAdditionalFlags 254 | ); 255 | 256 | [DllImport(Kernel32Dll, CharSet = CharSet.Unicode, BestFitMapping = false, ThrowOnUnmappableChar = true, SetLastError = true)] 257 | [return: MarshalAs(UnmanagedType.Bool)] 258 | public static extern bool FindNextFile(SafeFindHandle hFindFile, [In, Out] FindData lpFindFileData); 259 | 260 | [DllImport(Kernel32Dll, CharSet = CharSet.Unicode, BestFitMapping = false, ThrowOnUnmappableChar = true, SetLastError = true)] 261 | public static extern int GetFileAttributes(string lpFileName); 262 | 263 | [DllImport(Kernel32Dll, CharSet = CharSet.Unicode, BestFitMapping = false, ThrowOnUnmappableChar = true, SetLastError = true)] 264 | public static extern uint GetFullPathName( 265 | [MarshalAs(UnmanagedType.LPTStr)] 266 | string lpFileName, 267 | uint nBufferLength, 268 | [Out] 269 | System.Text.StringBuilder lpBuffer, 270 | System.Text.StringBuilder lpFilePart 271 | ); 272 | } 273 | 274 | //for mapping to the WIN32_FIND_DATA native structure 275 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 276 | public sealed class FindData 277 | { 278 | // NOTE: 279 | // Although it may seem correct to Marshal the string members of this class as UnmanagedType.LPWStr, they 280 | // must explicitly remain UnmanagedType.ByValTStr with the size constraints noted. Otherwise we end up with 281 | // COM Interop exceptions while trying to marshal the data across the PInvoke boundaries. 282 | public int fileAttributes; 283 | public System.Runtime.InteropServices.ComTypes.FILETIME creationTime; 284 | public System.Runtime.InteropServices.ComTypes.FILETIME lastAccessTime; 285 | public System.Runtime.InteropServices.ComTypes.FILETIME lastWriteTime; 286 | public int nFileSizeHigh; 287 | public int nFileSizeLow; 288 | public int dwReserved0; 289 | public int dwReserved1; 290 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] 291 | public string fileName; 292 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)] 293 | public string alternateFileName; 294 | } 295 | 296 | //A Win32 safe find handle in which a return value of -1 indicates it's invalid 297 | public sealed class SafeFindHandle : Microsoft.Win32.SafeHandles.SafeHandleMinusOneIsInvalid 298 | { 299 | public SafeFindHandle() 300 | : base(true) 301 | { 302 | return; 303 | } 304 | 305 | [System.Runtime.ConstrainedExecution.ReliabilityContract(System.Runtime.ConstrainedExecution.Consistency.WillNotCorruptState, System.Runtime.ConstrainedExecution.Cer.Success)] 306 | protected override bool ReleaseHandle() 307 | { 308 | return NativeMethods.FindClose(handle); 309 | } 310 | } 311 | 312 | // Refer https://msdn.microsoft.com/en-us/library/windows/desktop/gg258117(v=vs.85).aspx 313 | [Flags] 314 | public enum Attributes : uint 315 | { 316 | None = 0x00000000, 317 | Readonly = 0x00000001, 318 | Hidden = 0x00000002, 319 | System = 0x00000004, 320 | Directory = 0x00000010, 321 | Archive = 0x00000020, 322 | Device = 0x00000040, 323 | Normal = 0x00000080, 324 | Temporary = 0x00000100, 325 | SparseFile = 0x00000200, 326 | ReparsePoint = 0x00000400, 327 | Compressed = 0x00000800, 328 | Offline = 0x00001000, 329 | NotContentIndexed = 0x00002000, 330 | Encrypted = 0x00004000, 331 | IntegrityStream = 0x00008000, 332 | Virtual = 0x00010000, 333 | NoScrubData = 0x00020000, 334 | Write_Through = 0x80000000, 335 | Overlapped = 0x40000000, 336 | NoBuffering = 0x20000000, 337 | RandomAccess = 0x10000000, 338 | SequentialScan = 0x08000000, 339 | DeleteOnClose = 0x04000000, 340 | BackupSemantics = 0x02000000, 341 | PosixSemantics = 0x01000000, 342 | OpenReparsePoint = 0x00200000, 343 | OpenNoRecall = 0x00100000, 344 | FirstPipeInstance = 0x00080000 345 | } 346 | 347 | [Flags] 348 | public enum FindFlags 349 | { 350 | None = 0, 351 | CaseSensitive = 1, 352 | LargeFetch = 2, 353 | } 354 | 355 | public enum FindInfoLevel 356 | { 357 | Standard = 0, 358 | Basic = 1, 359 | } 360 | 361 | public enum FindSearchOps 362 | { 363 | NameMatch = 0, 364 | LimitToDirectories = 1, 365 | LimitToDevices = 2, 366 | } 367 | } 368 | '@ 369 | -------------------------------------------------------------------------------- /variablerehydration-task/v0/ps_modules/VstsTaskSdk/OutFunctions.ps1: -------------------------------------------------------------------------------- 1 | # TODO: It would be better if the Out-Default function resolved the underlying Out-Default 2 | # command in the begin block. This would allow for supporting other modules that override 3 | # Out-Default. 4 | $script:outDefaultCmdlet = $ExecutionContext.InvokeCommand.GetCmdlet("Microsoft.PowerShell.Core\Out-Default") 5 | 6 | ######################################## 7 | # Public functions. 8 | ######################################## 9 | function Out-Default { 10 | [CmdletBinding(ConfirmImpact = "Medium")] 11 | param( 12 | [Parameter(ValueFromPipeline = $true)] 13 | [System.Management.Automation.PSObject]$InputObject) 14 | 15 | begin { 16 | #Write-Host '[Entering Begin Out-Default]' 17 | $__sp = { & $script:outDefaultCmdlet @PSBoundParameters }.GetSteppablePipeline() 18 | $__sp.Begin($pscmdlet) 19 | #Write-Host '[Leaving Begin Out-Default]' 20 | } 21 | 22 | process { 23 | #Write-Host '[Entering Process Out-Default]' 24 | if ($_ -is [System.Management.Automation.ErrorRecord]) { 25 | Write-Verbose -Message 'Error record:' 4>&1 | Out-Default 26 | Write-Verbose -Message (Remove-TrailingNewLine (Out-String -InputObject $_ -Width 2147483647)) 4>&1 | Out-Default 27 | Write-Verbose -Message 'Script stack trace:' 4>&1 | Out-Default 28 | Write-Verbose -Message "$($_.ScriptStackTrace)" 4>&1 | Out-Default 29 | Write-Verbose -Message 'Exception:' 4>&1 | Out-Default 30 | Write-Verbose -Message $_.Exception.ToString() 4>&1 | Out-Default 31 | Write-TaskError -Message $_.Exception.Message 32 | } elseif ($_ -is [System.Management.Automation.WarningRecord]) { 33 | Write-TaskWarning -Message (Remove-TrailingNewLine (Out-String -InputObject $_ -Width 2147483647)) 34 | } elseif ($_ -is [System.Management.Automation.VerboseRecord]) { 35 | foreach ($private:str in (Format-DebugMessage -Object $_)) { 36 | Write-TaskVerbose -Message $private:str 37 | } 38 | } elseif ($_ -is [System.Management.Automation.DebugRecord]) { 39 | foreach ($private:str in (Format-DebugMessage -Object $_)) { 40 | Write-TaskDebug -Message $private:str 41 | } 42 | } else { 43 | # TODO: Consider using out-string here to control the width. As a security precaution it would actually be best to set it to max so wrapping doesn't interfere with secret masking. 44 | $__sp.Process($_) 45 | } 46 | 47 | #Write-Host '[Leaving Process Out-Default]' 48 | } 49 | 50 | end { 51 | #Write-Host '[Entering End Out-Default]' 52 | $__sp.End() 53 | #Write-Host '[Leaving End Out-Default]' 54 | } 55 | } 56 | 57 | ######################################## 58 | # Private functions. 59 | ######################################## 60 | function Format-DebugMessage { 61 | [CmdletBinding()] 62 | param([psobject]$Object) 63 | 64 | $private:str = Out-String -InputObject $Object -Width 2147483647 65 | $private:str = Remove-TrailingNewLine $private:str 66 | "$private:str".Replace("`r`n", "`n").Replace("`r", "`n").Split("`n"[0]) 67 | } 68 | 69 | function Remove-TrailingNewLine { 70 | [CmdletBinding()] 71 | param($Str) 72 | if ([object]::ReferenceEquals($Str, $null)) { 73 | return $Str 74 | } elseif ($Str.EndsWith("`r`n")) { 75 | return $Str.Substring(0, $Str.Length - 2) 76 | } else { 77 | return $Str 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /variablerehydration-task/v0/ps_modules/VstsTaskSdk/PSGetModuleInfo.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkdAgility/azure-devops-variable-tools/cc71f5f1648177772a8bb80473407752c50c0858/variablerehydration-task/v0/ps_modules/VstsTaskSdk/PSGetModuleInfo.xml -------------------------------------------------------------------------------- /variablerehydration-task/v0/ps_modules/VstsTaskSdk/Strings/resources.resjson/de-de/resources.resjson: -------------------------------------------------------------------------------- 1 | { 2 | "loc.messages.PSLIB_ContainerPathNotFound0": "Der Containerpfad wurde nicht gefunden: \"{0}\".", 3 | "loc.messages.PSLIB_EndpointAuth0": "\"{0}\"-Dienstendpunkt-Anmeldeinformationen", 4 | "loc.messages.PSLIB_EndpointUrl0": "\"{0}\"-Dienstendpunkt-URL", 5 | "loc.messages.PSLIB_EnumeratingSubdirectoriesFailedForPath0": "Fehler beim Aufzählen von Unterverzeichnissen für den folgenden Pfad: \"{0}\"", 6 | "loc.messages.PSLIB_FileNotFound0": "Die Datei wurde nicht gefunden: \"{0}\".", 7 | "loc.messages.PSLIB_Input0": "\"{0}\"-Eingabe", 8 | "loc.messages.PSLIB_InvalidPattern0": "Ungültiges Muster: \"{0}\"", 9 | "loc.messages.PSLIB_LeafPathNotFound0": "Der Blattpfad wurde nicht gefunden: \"{0}\".", 10 | "loc.messages.PSLIB_PathLengthNotReturnedFor0": "Fehler bei der Normalisierung bzw. Erweiterung des Pfads. Die Pfadlänge wurde vom Kernel32-Subsystem nicht zurückgegeben für: \"{0}\"", 11 | "loc.messages.PSLIB_PathNotFound0": "Der Pfad wurde nicht gefunden: \"{0}\".", 12 | "loc.messages.PSLIB_Process0ExitedWithCode1": "Der Prozess \"{0}\" wurde mit dem Code \"{1}\" beendet.", 13 | "loc.messages.PSLIB_Required0": "Erforderlich: {0}", 14 | "loc.messages.PSLIB_StringFormatFailed": "Fehler beim Zeichenfolgenformat.", 15 | "loc.messages.PSLIB_StringResourceKeyNotFound0": "Der Zeichenfolgen-Ressourcenschlüssel wurde nicht gefunden: \"{0}\".", 16 | "loc.messages.PSLIB_TaskVariable0": "\"{0}\"-Taskvariable" 17 | } -------------------------------------------------------------------------------- /variablerehydration-task/v0/ps_modules/VstsTaskSdk/Strings/resources.resjson/en-US/resources.resjson: -------------------------------------------------------------------------------- 1 | { 2 | "loc.messages.PSLIB_ContainerPathNotFound0": "Container path not found: '{0}'", 3 | "loc.messages.PSLIB_EndpointAuth0": "'{0}' service endpoint credentials", 4 | "loc.messages.PSLIB_EndpointUrl0": "'{0}' service endpoint URL", 5 | "loc.messages.PSLIB_EnumeratingSubdirectoriesFailedForPath0": "Enumerating subdirectories failed for path: '{0}'", 6 | "loc.messages.PSLIB_FileNotFound0": "File not found: '{0}'", 7 | "loc.messages.PSLIB_Input0": "'{0}' input", 8 | "loc.messages.PSLIB_InvalidPattern0": "Invalid pattern: '{0}'", 9 | "loc.messages.PSLIB_LeafPathNotFound0": "Leaf path not found: '{0}'", 10 | "loc.messages.PSLIB_PathLengthNotReturnedFor0": "Path normalization/expansion failed. The path length was not returned by the Kernel32 subsystem for: '{0}'", 11 | "loc.messages.PSLIB_PathNotFound0": "Path not found: '{0}'", 12 | "loc.messages.PSLIB_Process0ExitedWithCode1": "Process '{0}' exited with code '{1}'.", 13 | "loc.messages.PSLIB_Required0": "Required: {0}", 14 | "loc.messages.PSLIB_StringFormatFailed": "String format failed.", 15 | "loc.messages.PSLIB_StringResourceKeyNotFound0": "String resource key not found: '{0}'", 16 | "loc.messages.PSLIB_TaskVariable0": "'{0}' task variable" 17 | } -------------------------------------------------------------------------------- /variablerehydration-task/v0/ps_modules/VstsTaskSdk/Strings/resources.resjson/es-es/resources.resjson: -------------------------------------------------------------------------------- 1 | { 2 | "loc.messages.PSLIB_ContainerPathNotFound0": "No se encuentra la ruta de acceso del contenedor: '{0}'", 3 | "loc.messages.PSLIB_EndpointAuth0": "Credenciales del punto de conexión de servicio '{0}'", 4 | "loc.messages.PSLIB_EndpointUrl0": "URL del punto de conexión de servicio '{0}'", 5 | "loc.messages.PSLIB_EnumeratingSubdirectoriesFailedForPath0": "No se pudieron enumerar los subdirectorios de la ruta de acceso: '{0}'", 6 | "loc.messages.PSLIB_FileNotFound0": "Archivo no encontrado: '{0}'", 7 | "loc.messages.PSLIB_Input0": "Entrada '{0}'", 8 | "loc.messages.PSLIB_InvalidPattern0": "Patrón no válido: '{0}'", 9 | "loc.messages.PSLIB_LeafPathNotFound0": "No se encuentra la ruta de acceso de la hoja: '{0}'", 10 | "loc.messages.PSLIB_PathLengthNotReturnedFor0": "No se pudo normalizar o expandir la ruta de acceso. El subsistema Kernel32 no devolvió la longitud de la ruta de acceso para: '{0}'", 11 | "loc.messages.PSLIB_PathNotFound0": "No se encuentra la ruta de acceso: '{0}'", 12 | "loc.messages.PSLIB_Process0ExitedWithCode1": "El proceso '{0}' finalizó con el código '{1}'.", 13 | "loc.messages.PSLIB_Required0": "Se requiere: {0}", 14 | "loc.messages.PSLIB_StringFormatFailed": "Error de formato de cadena.", 15 | "loc.messages.PSLIB_StringResourceKeyNotFound0": "No se encuentra la clave de recurso de la cadena: '{0}'", 16 | "loc.messages.PSLIB_TaskVariable0": "Variable de tarea '{0}'" 17 | } -------------------------------------------------------------------------------- /variablerehydration-task/v0/ps_modules/VstsTaskSdk/Strings/resources.resjson/fr-fr/resources.resjson: -------------------------------------------------------------------------------- 1 | { 2 | "loc.messages.PSLIB_ContainerPathNotFound0": "Le chemin du conteneur est introuvable : '{0}'", 3 | "loc.messages.PSLIB_EndpointAuth0": "Informations d'identification du point de terminaison de service '{0}'", 4 | "loc.messages.PSLIB_EndpointUrl0": "URL du point de terminaison de service '{0}'", 5 | "loc.messages.PSLIB_EnumeratingSubdirectoriesFailedForPath0": "Échec de l'énumération des sous-répertoires pour le chemin : '{0}'", 6 | "loc.messages.PSLIB_FileNotFound0": "Fichier introuvable : {0}.", 7 | "loc.messages.PSLIB_Input0": "Entrée '{0}'", 8 | "loc.messages.PSLIB_InvalidPattern0": "Modèle non valide : '{0}'", 9 | "loc.messages.PSLIB_LeafPathNotFound0": "Le chemin feuille est introuvable : '{0}'", 10 | "loc.messages.PSLIB_PathLengthNotReturnedFor0": "Échec de la normalisation/l'expansion du chemin. La longueur du chemin n'a pas été retournée par le sous-système Kernel32 pour : '{0}'", 11 | "loc.messages.PSLIB_PathNotFound0": "Chemin introuvable : '{0}'", 12 | "loc.messages.PSLIB_Process0ExitedWithCode1": "Le processus '{0}' s'est arrêté avec le code '{1}'.", 13 | "loc.messages.PSLIB_Required0": "Obligatoire : {0}", 14 | "loc.messages.PSLIB_StringFormatFailed": "Échec du format de la chaîne.", 15 | "loc.messages.PSLIB_StringResourceKeyNotFound0": "Clé de la ressource de type chaîne introuvable : '{0}'", 16 | "loc.messages.PSLIB_TaskVariable0": "Variable de tâche '{0}'" 17 | } -------------------------------------------------------------------------------- /variablerehydration-task/v0/ps_modules/VstsTaskSdk/Strings/resources.resjson/it-IT/resources.resjson: -------------------------------------------------------------------------------- 1 | { 2 | "loc.messages.PSLIB_ContainerPathNotFound0": "Percorso del contenitore non trovato: '{0}'", 3 | "loc.messages.PSLIB_EndpointAuth0": "Credenziali dell'endpoint servizio '{0}'", 4 | "loc.messages.PSLIB_EndpointUrl0": "URL dell'endpoint servizio '{0}'", 5 | "loc.messages.PSLIB_EnumeratingSubdirectoriesFailedForPath0": "L'enumerazione delle sottodirectory per il percorso '{0}' non è riuscita", 6 | "loc.messages.PSLIB_FileNotFound0": "File non trovato: '{0}'", 7 | "loc.messages.PSLIB_Input0": "Input di '{0}'", 8 | "loc.messages.PSLIB_InvalidPattern0": "Criterio non valido: '{0}'", 9 | "loc.messages.PSLIB_LeafPathNotFound0": "Percorso foglia non trovato: '{0}'", 10 | "loc.messages.PSLIB_PathLengthNotReturnedFor0": "La normalizzazione o l'espansione del percorso non è riuscita. Il sottosistema Kernel32 non ha restituito la lunghezza del percorso per '{0}'", 11 | "loc.messages.PSLIB_PathNotFound0": "Percorso non trovato: '{0}'", 12 | "loc.messages.PSLIB_Process0ExitedWithCode1": "Il processo '{0}' è stato terminato ed è stato restituito il codice '{1}'.", 13 | "loc.messages.PSLIB_Required0": "Obbligatorio: {0}", 14 | "loc.messages.PSLIB_StringFormatFailed": "Errore nel formato della stringa.", 15 | "loc.messages.PSLIB_StringResourceKeyNotFound0": "La chiave della risorsa stringa non è stata trovata: '{0}'", 16 | "loc.messages.PSLIB_TaskVariable0": "Variabile dell'attività '{0}'" 17 | } -------------------------------------------------------------------------------- /variablerehydration-task/v0/ps_modules/VstsTaskSdk/Strings/resources.resjson/ja-jp/resources.resjson: -------------------------------------------------------------------------------- 1 | { 2 | "loc.messages.PSLIB_ContainerPathNotFound0": "コンテナーのパスが見つかりません: '{0}'", 3 | "loc.messages.PSLIB_EndpointAuth0": "'{0}' サービス エンドポイントの資格情報", 4 | "loc.messages.PSLIB_EndpointUrl0": "'{0}' サービス エンドポイントの URL", 5 | "loc.messages.PSLIB_EnumeratingSubdirectoriesFailedForPath0": "パス '{0}' のサブディレクトリを列挙できませんでした", 6 | "loc.messages.PSLIB_FileNotFound0": "ファイルが見つかりません: '{0}'", 7 | "loc.messages.PSLIB_Input0": "'{0}' 入力", 8 | "loc.messages.PSLIB_InvalidPattern0": "使用できないパターンです: '{0}'", 9 | "loc.messages.PSLIB_LeafPathNotFound0": "リーフ パスが見つかりません: '{0}'", 10 | "loc.messages.PSLIB_PathLengthNotReturnedFor0": "パスの正規化/展開に失敗しました。Kernel32 サブシステムからパス '{0}' の長さが返されませんでした", 11 | "loc.messages.PSLIB_PathNotFound0": "パスが見つかりません: '{0}'", 12 | "loc.messages.PSLIB_Process0ExitedWithCode1": "プロセス '{0}' がコード '{1}' で終了しました。", 13 | "loc.messages.PSLIB_Required0": "必要: {0}", 14 | "loc.messages.PSLIB_StringFormatFailed": "文字列のフォーマットに失敗しました。", 15 | "loc.messages.PSLIB_StringResourceKeyNotFound0": "文字列のリソース キーが見つかりません: '{0}'", 16 | "loc.messages.PSLIB_TaskVariable0": "'{0}' タスク変数" 17 | } -------------------------------------------------------------------------------- /variablerehydration-task/v0/ps_modules/VstsTaskSdk/Strings/resources.resjson/ko-KR/resources.resjson: -------------------------------------------------------------------------------- 1 | { 2 | "loc.messages.PSLIB_ContainerPathNotFound0": "컨테이너 경로를 찾을 수 없음: '{0}'", 3 | "loc.messages.PSLIB_EndpointAuth0": "'{0}' 서비스 끝점 자격 증명", 4 | "loc.messages.PSLIB_EndpointUrl0": "'{0}' 서비스 끝점 URL", 5 | "loc.messages.PSLIB_EnumeratingSubdirectoriesFailedForPath0": "경로에 대해 하위 디렉터리를 열거하지 못함: '{0}'", 6 | "loc.messages.PSLIB_FileNotFound0": "{0} 파일을 찾을 수 없습니다.", 7 | "loc.messages.PSLIB_Input0": "'{0}' 입력", 8 | "loc.messages.PSLIB_InvalidPattern0": "잘못된 패턴: '{0}'", 9 | "loc.messages.PSLIB_LeafPathNotFound0": "Leaf 경로를 찾을 수 없음: '{0}'", 10 | "loc.messages.PSLIB_PathLengthNotReturnedFor0": "경로 정규화/확장에 실패했습니다. 다음에 대해 Kernel32 subsystem에서 경로 길이를 반환하지 않음: '{0}'", 11 | "loc.messages.PSLIB_PathNotFound0": "경로를 찾을 수 없음: '{0}'", 12 | "loc.messages.PSLIB_Process0ExitedWithCode1": "'{1}' 코드로 '{0}' 프로세스가 종료되었습니다.", 13 | "loc.messages.PSLIB_Required0": "필수: {0}", 14 | "loc.messages.PSLIB_StringFormatFailed": "문자열을 포맷하지 못했습니다.", 15 | "loc.messages.PSLIB_StringResourceKeyNotFound0": "문자열 리소스 키를 찾을 수 없음: '{0}'", 16 | "loc.messages.PSLIB_TaskVariable0": "'{0}' 작업 변수" 17 | } -------------------------------------------------------------------------------- /variablerehydration-task/v0/ps_modules/VstsTaskSdk/Strings/resources.resjson/ru-RU/resources.resjson: -------------------------------------------------------------------------------- 1 | { 2 | "loc.messages.PSLIB_ContainerPathNotFound0": "Путь к контейнеру не найден: \"{0}\".", 3 | "loc.messages.PSLIB_EndpointAuth0": "Учетные данные конечной точки службы \"{0}\"", 4 | "loc.messages.PSLIB_EndpointUrl0": "URL-адрес конечной точки службы \"{0}\"", 5 | "loc.messages.PSLIB_EnumeratingSubdirectoriesFailedForPath0": "Сбой перечисления подкаталогов для пути: \"{0}\".", 6 | "loc.messages.PSLIB_FileNotFound0": "Файл не найден: \"{0}\".", 7 | "loc.messages.PSLIB_Input0": "Входные данные \"{0}\".", 8 | "loc.messages.PSLIB_InvalidPattern0": "Недопустимый шаблон: \"{0}\".", 9 | "loc.messages.PSLIB_LeafPathNotFound0": "Путь к конечному объекту не найден: \"{0}\".", 10 | "loc.messages.PSLIB_PathLengthNotReturnedFor0": "Сбой нормализации и расширения пути. Длина пути не была возвращена подсистемой Kernel32 для: \"{0}\".", 11 | "loc.messages.PSLIB_PathNotFound0": "Путь не найден: \"{0}\".", 12 | "loc.messages.PSLIB_Process0ExitedWithCode1": "Процесс \"{0}\" завершил работу с кодом \"{1}\".", 13 | "loc.messages.PSLIB_Required0": "Требуется: {0}", 14 | "loc.messages.PSLIB_StringFormatFailed": "Сбой формата строки.", 15 | "loc.messages.PSLIB_StringResourceKeyNotFound0": "Ключ ресурса строки не найден: \"{0}\".", 16 | "loc.messages.PSLIB_TaskVariable0": "Переменная задачи \"{0}\"" 17 | } -------------------------------------------------------------------------------- /variablerehydration-task/v0/ps_modules/VstsTaskSdk/Strings/resources.resjson/zh-CN/resources.resjson: -------------------------------------------------------------------------------- 1 | { 2 | "loc.messages.PSLIB_ContainerPathNotFound0": "找不到容器路径:“{0}”", 3 | "loc.messages.PSLIB_EndpointAuth0": "“{0}”服务终结点凭据", 4 | "loc.messages.PSLIB_EndpointUrl0": "“{0}”服务终结点 URL", 5 | "loc.messages.PSLIB_EnumeratingSubdirectoriesFailedForPath0": "枚举路径的子目录失败:“{0}”", 6 | "loc.messages.PSLIB_FileNotFound0": "找不到文件: {0}。", 7 | "loc.messages.PSLIB_Input0": "“{0}”输入", 8 | "loc.messages.PSLIB_InvalidPattern0": "无效的模式:“{0}”", 9 | "loc.messages.PSLIB_LeafPathNotFound0": "找不到叶路径:“{0}”", 10 | "loc.messages.PSLIB_PathLengthNotReturnedFor0": "路径规范化/扩展失败。路径长度不是由“{0}”的 Kernel32 子系统返回的", 11 | "loc.messages.PSLIB_PathNotFound0": "找不到路径:“{0}”", 12 | "loc.messages.PSLIB_Process0ExitedWithCode1": "过程“{0}”已退出,代码为“{1}”。", 13 | "loc.messages.PSLIB_Required0": "必需: {0}", 14 | "loc.messages.PSLIB_StringFormatFailed": "字符串格式无效。", 15 | "loc.messages.PSLIB_StringResourceKeyNotFound0": "找不到字符串资源关键字:“{0}”", 16 | "loc.messages.PSLIB_TaskVariable0": "“{0}”任务变量" 17 | } -------------------------------------------------------------------------------- /variablerehydration-task/v0/ps_modules/VstsTaskSdk/Strings/resources.resjson/zh-TW/resources.resjson: -------------------------------------------------------------------------------- 1 | { 2 | "loc.messages.PSLIB_ContainerPathNotFound0": "找不到容器路徑: '{0}'", 3 | "loc.messages.PSLIB_EndpointAuth0": "'{0}' 服務端點認證", 4 | "loc.messages.PSLIB_EndpointUrl0": "'{0}' 服務端點 URL", 5 | "loc.messages.PSLIB_EnumeratingSubdirectoriesFailedForPath0": "為路徑列舉子目錄失敗: '{0}'", 6 | "loc.messages.PSLIB_FileNotFound0": "找不到檔案: '{0}'", 7 | "loc.messages.PSLIB_Input0": "'{0}' 輸入", 8 | "loc.messages.PSLIB_InvalidPattern0": "模式無效: '{0}'", 9 | "loc.messages.PSLIB_LeafPathNotFound0": "找不到分葉路徑: '{0}'", 10 | "loc.messages.PSLIB_PathLengthNotReturnedFor0": "路徑正規化/展開失敗。Kernel32 子系統未傳回 '{0}' 的路徑長度", 11 | "loc.messages.PSLIB_PathNotFound0": "找不到路徑: '{0}'", 12 | "loc.messages.PSLIB_Process0ExitedWithCode1": "處理序 '{0}' 以返回碼 '{1}' 結束。", 13 | "loc.messages.PSLIB_Required0": "必要項: {0}", 14 | "loc.messages.PSLIB_StringFormatFailed": "字串格式失敗。", 15 | "loc.messages.PSLIB_StringResourceKeyNotFound0": "找不到字串資源索引鍵: '{0}'", 16 | "loc.messages.PSLIB_TaskVariable0": "'{0}' 工作變數" 17 | } -------------------------------------------------------------------------------- /variablerehydration-task/v0/ps_modules/VstsTaskSdk/ToolFunctions.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Asserts that a path exists. Throws if the path does not exist. 4 | 5 | .PARAMETER PassThru 6 | True to return the path. 7 | #> 8 | function Assert-Path { 9 | [CmdletBinding()] 10 | param( 11 | [Parameter(Mandatory = $true)] 12 | [string]$LiteralPath, 13 | [Microsoft.PowerShell.Commands.TestPathType]$PathType = [Microsoft.PowerShell.Commands.TestPathType]::Any, 14 | [switch]$PassThru) 15 | 16 | if ($PathType -eq [Microsoft.PowerShell.Commands.TestPathType]::Any) { 17 | Write-Verbose "Asserting path exists: '$LiteralPath'" 18 | } else { 19 | Write-Verbose "Asserting $("$PathType".ToLowerInvariant()) path exists: '$LiteralPath'" 20 | } 21 | 22 | if (Test-Path -LiteralPath $LiteralPath -PathType $PathType) { 23 | if ($PassThru) { 24 | return $LiteralPath 25 | } 26 | 27 | return 28 | } 29 | 30 | $resourceKey = switch ($PathType) { 31 | ([Microsoft.PowerShell.Commands.TestPathType]::Container) { "PSLIB_ContainerPathNotFound0" ; break } 32 | ([Microsoft.PowerShell.Commands.TestPathType]::Leaf) { "PSLIB_LeafPathNotFound0" ; break } 33 | default { "PSLIB_PathNotFound0" } 34 | } 35 | 36 | throw (Get-LocString -Key $resourceKey -ArgumentList $LiteralPath) 37 | } 38 | 39 | <# 40 | .SYNOPSIS 41 | Executes an external program. 42 | 43 | .DESCRIPTION 44 | Executes an external program and waits for the process to exit. 45 | 46 | After calling this command, the exit code of the process can be retrieved from the variable $LASTEXITCODE. 47 | 48 | .PARAMETER Encoding 49 | This parameter not required for most scenarios. Indicates how to interpret the encoding from the external program. An example use case would be if an external program outputs UTF-16 XML and the output needs to be parsed. 50 | 51 | .PARAMETER RequireExitCodeZero 52 | Indicates whether to write an error to the error pipeline if the exit code is not zero. 53 | #> 54 | function Invoke-Tool { # TODO: RENAME TO INVOKE-PROCESS? 55 | [CmdletBinding()] 56 | param( 57 | [ValidatePattern('^[^\r\n]*$')] 58 | [Parameter(Mandatory = $true)] 59 | [string]$FileName, 60 | [ValidatePattern('^[^\r\n]*$')] 61 | [Parameter()] 62 | [string]$Arguments, 63 | [string]$WorkingDirectory, 64 | [System.Text.Encoding]$Encoding, 65 | [switch]$RequireExitCodeZero) 66 | 67 | Trace-EnteringInvocation $MyInvocation 68 | $isPushed = $false 69 | $originalEncoding = $null 70 | try { 71 | if ($Encoding) { 72 | $originalEncoding = [System.Console]::OutputEncoding 73 | [System.Console]::OutputEncoding = $Encoding 74 | } 75 | 76 | if ($WorkingDirectory) { 77 | Push-Location -LiteralPath $WorkingDirectory -ErrorAction Stop 78 | $isPushed = $true 79 | } 80 | 81 | $FileName = $FileName.Replace('"', '').Replace("'", "''") 82 | Write-Host "##[command]""$FileName"" $Arguments" 83 | Invoke-Expression "& '$FileName' --% $Arguments" 84 | Write-Verbose "Exit code: $LASTEXITCODE" 85 | if ($RequireExitCodeZero -and $LASTEXITCODE -ne 0) { 86 | Write-Error (Get-LocString -Key PSLIB_Process0ExitedWithCode1 -ArgumentList ([System.IO.Path]::GetFileName($FileName)), $LASTEXITCODE) 87 | } 88 | } finally { 89 | if ($originalEncoding) { 90 | [System.Console]::OutputEncoding = $originalEncoding 91 | } 92 | 93 | if ($isPushed) { 94 | Pop-Location 95 | } 96 | 97 | Trace-LeavingInvocation $MyInvocation 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /variablerehydration-task/v0/ps_modules/VstsTaskSdk/TraceFunctions.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Writes verbose information about the invocation being entered. 4 | 5 | .DESCRIPTION 6 | Used to trace verbose information when entering a function/script. Writes an entering message followed by a short description of the invocation. Additionally each bound parameter and unbound argument is also traced. 7 | 8 | .PARAMETER Parameter 9 | Wildcard pattern to control which bound parameters are traced. 10 | #> 11 | function Trace-EnteringInvocation { 12 | [CmdletBinding()] 13 | param( 14 | [Parameter(Mandatory = $true)] 15 | [System.Management.Automation.InvocationInfo]$InvocationInfo, 16 | [string[]]$Parameter = '*') 17 | 18 | Write-Verbose "Entering $(Get-InvocationDescription $InvocationInfo)." 19 | $OFS = ", " 20 | if ($InvocationInfo.BoundParameters.Count -and $Parameter.Count) { 21 | if ($Parameter.Count -eq 1 -and $Parameter[0] -eq '*') { 22 | # Trace all parameters. 23 | foreach ($key in $InvocationInfo.BoundParameters.Keys) { 24 | Write-Verbose " $($key): '$($InvocationInfo.BoundParameters[$key])'" 25 | } 26 | } else { 27 | # Trace matching parameters. 28 | foreach ($key in $InvocationInfo.BoundParameters.Keys) { 29 | foreach ($p in $Parameter) { 30 | if ($key -like $p) { 31 | Write-Verbose " $($key): '$($InvocationInfo.BoundParameters[$key])'" 32 | break 33 | } 34 | } 35 | } 36 | } 37 | } 38 | 39 | # Trace all unbound arguments. 40 | if (@($InvocationInfo.UnboundArguments).Count) { 41 | for ($i = 0 ; $i -lt $InvocationInfo.UnboundArguments.Count ; $i++) { 42 | Write-Verbose " args[$i]: '$($InvocationInfo.UnboundArguments[$i])'" 43 | } 44 | } 45 | } 46 | 47 | <# 48 | .SYNOPSIS 49 | Writes verbose information about the invocation being left. 50 | 51 | .DESCRIPTION 52 | Used to trace verbose information when leaving a function/script. Writes a leaving message followed by a short description of the invocation. 53 | #> 54 | function Trace-LeavingInvocation { 55 | [CmdletBinding()] 56 | param( 57 | [Parameter(Mandatory = $true)] 58 | [System.Management.Automation.InvocationInfo]$InvocationInfo) 59 | 60 | Write-Verbose "Leaving $(Get-InvocationDescription $InvocationInfo)." 61 | } 62 | 63 | <# 64 | .SYNOPSIS 65 | Writes verbose information about paths. 66 | 67 | .DESCRIPTION 68 | Writes verbose information about the paths. The paths are sorted and a the common root is written only once, followed by each relative path. 69 | 70 | .PARAMETER PassThru 71 | Indicates whether to return the sorted paths. 72 | #> 73 | function Trace-Path { 74 | [CmdletBinding()] 75 | param( 76 | [string[]]$Path, 77 | [switch]$PassThru) 78 | 79 | if ($Path.Count -eq 0) { 80 | Write-Verbose "No paths." 81 | if ($PassThru) { 82 | $Path 83 | } 84 | } elseif ($Path.Count -eq 1) { 85 | Write-Verbose "Path: $($Path[0])" 86 | if ($PassThru) { 87 | $Path 88 | } 89 | } else { 90 | # Find the greatest common root. 91 | $sorted = $Path | Sort-Object 92 | $firstPath = $sorted[0].ToCharArray() 93 | $lastPath = $sorted[-1].ToCharArray() 94 | $commonEndIndex = 0 95 | $j = if ($firstPath.Length -lt $lastPath.Length) { $firstPath.Length } else { $lastPath.Length } 96 | for ($i = 0 ; $i -lt $j ; $i++) { 97 | if ($firstPath[$i] -eq $lastPath[$i]) { 98 | if ($firstPath[$i] -eq '\') { 99 | $commonEndIndex = $i 100 | } 101 | } else { 102 | break 103 | } 104 | } 105 | 106 | if ($commonEndIndex -eq 0) { 107 | # No common root. 108 | Write-Verbose "Paths:" 109 | foreach ($p in $sorted) { 110 | Write-Verbose " $p" 111 | } 112 | } else { 113 | Write-Verbose "Paths: $($Path[0].Substring(0, $commonEndIndex + 1))" 114 | foreach ($p in $sorted) { 115 | Write-Verbose " $($p.Substring($commonEndIndex + 1))" 116 | } 117 | } 118 | 119 | if ($PassThru) { 120 | $sorted 121 | } 122 | } 123 | } 124 | 125 | ######################################## 126 | # Private functions. 127 | ######################################## 128 | function Get-InvocationDescription { 129 | [CmdletBinding()] 130 | param([System.Management.Automation.InvocationInfo]$InvocationInfo) 131 | 132 | if ($InvocationInfo.MyCommand.Path) { 133 | $InvocationInfo.MyCommand.Path 134 | } elseif ($InvocationInfo.MyCommand.Name) { 135 | $InvocationInfo.MyCommand.Name 136 | } else { 137 | $InvocationInfo.MyCommand.CommandType 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /variablerehydration-task/v0/ps_modules/VstsTaskSdk/VstsTaskSdk.psd1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nkdAgility/azure-devops-variable-tools/cc71f5f1648177772a8bb80473407752c50c0858/variablerehydration-task/v0/ps_modules/VstsTaskSdk/VstsTaskSdk.psd1 -------------------------------------------------------------------------------- /variablerehydration-task/v0/ps_modules/VstsTaskSdk/VstsTaskSdk.psm1: -------------------------------------------------------------------------------- 1 | [CmdletBinding()] 2 | param( 3 | [ValidateNotNull()] 4 | [Parameter()] 5 | [hashtable]$ModuleParameters = @{ }) 6 | 7 | if ($host.Name -ne 'ConsoleHost') { 8 | Write-Warning "VstsTaskSdk is designed for use with powershell.exe (ConsoleHost). Output may be different when used with other hosts." 9 | } 10 | 11 | # Private module variables. 12 | [bool]$script:nonInteractive = "$($ModuleParameters['NonInteractive'])" -eq 'true' 13 | Write-Verbose "NonInteractive: $script:nonInteractive" 14 | 15 | # Import/export functions. 16 | . "$PSScriptRoot\FindFunctions.ps1" 17 | . "$PSScriptRoot\InputFunctions.ps1" 18 | . "$PSScriptRoot\LocalizationFunctions.ps1" 19 | . "$PSScriptRoot\LoggingCommandFunctions.ps1" 20 | . "$PSScriptRoot\LongPathFunctions.ps1" 21 | . "$PSScriptRoot\ServerOMFunctions.ps1" 22 | . "$PSScriptRoot\ToolFunctions.ps1" 23 | . "$PSScriptRoot\TraceFunctions.ps1" 24 | . "$PSScriptRoot\OutFunctions.ps1" # Load the out functions after all of the other functions are loaded. 25 | Export-ModuleMember -Function @( 26 | # Find functions. 27 | 'Find-Files' 28 | # Input functions. 29 | 'Get-Endpoint' 30 | 'Get-Input' 31 | 'Get-TaskVariable' 32 | 'Get-TaskVariableInfo' 33 | 'Set-TaskVariable' 34 | # Localization functions. 35 | 'Get-LocString' 36 | 'Import-LocStrings' 37 | # Logging command functions. 38 | 'Write-AddAttachment' 39 | 'Write-AddBuildTag' 40 | 'Write-AssociateArtifact' 41 | 'Write-LogDetail' 42 | 'Write-SetProgress' 43 | 'Write-SetResult' 44 | 'Write-SetSecret' 45 | 'Write-SetVariable' 46 | 'Write-TaskDebug' 47 | 'Write-TaskError' 48 | 'Write-TaskVerbose' 49 | 'Write-TaskWarning' 50 | 'Write-UpdateBuildNumber' 51 | 'Write-UploadArtifact' 52 | 'Write-UploadBuildLog' 53 | # Out functions. 54 | 'Out-Default' 55 | # Server OM functions. 56 | 'Get-AssemblyReference' 57 | 'Get-TfsClientCredentials' 58 | 'Get-TfsService' 59 | 'Get-VssCredentials' 60 | 'Get-VssHttpClient' 61 | # Tool functions. 62 | 'Assert-Path' 63 | 'Invoke-Tool' 64 | # Trace functions. 65 | 'Trace-EnteringInvocation' 66 | 'Trace-LeavingInvocation' 67 | 'Trace-Path' 68 | ) 69 | 70 | # Special internal exception type to control the flow. Not currently intended 71 | # for public usage and subject to change. If the type has already 72 | # been loaded once, then it is not loaded again. 73 | Write-Verbose "Adding exceptions types." 74 | Add-Type -WarningAction SilentlyContinue -Debug:$false -TypeDefinition @' 75 | namespace VstsTaskSdk 76 | { 77 | public class TerminationException : System.Exception 78 | { 79 | public TerminationException(System.String message) : base(message) { } 80 | } 81 | } 82 | '@ 83 | 84 | # Override Out-Default globally. 85 | $null = New-Item -Force -Path "function:\global:Out-Default" -Value (Get-Command -CommandType Function -Name Out-Default -ListImported) 86 | New-Alias -Name Out-Default -Value "global:Out-Default" -Scope global 87 | 88 | # Perform some initialization in a script block to enable merging the pipelines. 89 | $scriptText = @" 90 | # Load the SDK resource strings. 91 | Import-LocStrings "$PSScriptRoot\lib.json" 92 | 93 | # Load the module that contains ConvertTo-SecureString. 94 | if (!(Get-Module -Name Microsoft.PowerShell.Security)) { 95 | Write-Verbose "Importing the module 'Microsoft.PowerShell.Security'." 96 | Import-Module -Name Microsoft.PowerShell.Security 2>&1 | 97 | ForEach-Object { 98 | if (`$_ -is [System.Management.Automation.ErrorRecord]) { 99 | Write-Verbose `$_.Exception.Message 100 | } else { 101 | ,`$_ 102 | } 103 | } 104 | } 105 | "@ 106 | . ([scriptblock]::Create($scriptText)) 2>&1 3>&1 4>&1 5>&1 | Out-Default 107 | 108 | # Create Invoke-VstsTaskScript in a special way so it is not bound to the module. 109 | # Otherwise calling the task script block would run within the module context. 110 | # 111 | # An alternative way to solve the problem is to close the script block (i.e. closure). 112 | # However, that introduces a different problem. Closed script blocks are created within 113 | # a dynamic module. Each module gets it's own session state separate from the global 114 | # session state. When running in a regular script context, Import-Module calls import 115 | # the target module into the global session state. When running in a module context, 116 | # Import-Module calls import the target module into the caller module's session state. 117 | # 118 | # The goal of a task may include executing ad-hoc scripts. Therefore, task scripts 119 | # should run in regular script context. The end user specifying an ad-hoc script expects 120 | # the module import rules to be consistent with the default behavior (i.e. imported 121 | # into the global session state). 122 | $null = New-Item -Force -Path "function:\global:Invoke-VstsTaskScript" -Value ([scriptblock]::Create(@' 123 | [CmdletBinding()] 124 | param( 125 | [Parameter(Mandatory = $true)] 126 | [scriptblock]$ScriptBlock) 127 | 128 | try { 129 | $global:ErrorActionPreference = 'Stop' 130 | 131 | # Initialize the environment. 132 | $vstsModule = Get-Module -Name VstsTaskSdk 133 | Write-Verbose "$($vstsModule.Name) $($vstsModule.Version) commit $($vstsModule.PrivateData.PSData.CommitHash)" 4>&1 | Out-Default 134 | & $vstsModule Initialize-Inputs 4>&1 | Out-Default 135 | 136 | # Remove the local variable before calling the user's script. 137 | Remove-Variable -Name vstsModule 138 | 139 | # Call the user's script. 140 | $ScriptBlock | 141 | ForEach-Object { 142 | # Remove the scriptblock variable before calling it. 143 | Remove-Variable -Name ScriptBlock 144 | & $_ 2>&1 3>&1 4>&1 5>&1 | Out-Default 145 | } 146 | } catch [VstsTaskSdk.TerminationException] { 147 | # Special internal exception type to control the flow. Not currently intended 148 | # for public usage and subject to change. 149 | Write-Verbose "Task script terminated." 4>&1 | Out-Default 150 | } catch { 151 | Write-Verbose "Caught exception from task script." 4>&1 | Out-Default 152 | $_ | Out-Default 153 | Write-Host "##vso[task.complete result=Failed]" 154 | } 155 | '@)) 156 | -------------------------------------------------------------------------------- /variablerehydration-task/v0/ps_modules/VstsTaskSdk/lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "messages": { 3 | "PSLIB_ContainerPathNotFound0": "Container path not found: '{0}'", 4 | "PSLIB_EndpointAuth0": "'{0}' service endpoint credentials", 5 | "PSLIB_EndpointUrl0": "'{0}' service endpoint URL", 6 | "PSLIB_EnumeratingSubdirectoriesFailedForPath0": "Enumerating subdirectories failed for path: '{0}'", 7 | "PSLIB_FileNotFound0": "File not found: '{0}'", 8 | "PSLIB_Input0": "'{0}' input", 9 | "PSLIB_InvalidPattern0": "Invalid pattern: '{0}'", 10 | "PSLIB_LeafPathNotFound0": "Leaf path not found: '{0}'", 11 | "PSLIB_PathLengthNotReturnedFor0": "Path normalization/expansion failed. The path length was not returned by the Kernel32 subsystem for: '{0}'", 12 | "PSLIB_PathNotFound0": "Path not found: '{0}'", 13 | "PSLIB_Process0ExitedWithCode1": "Process '{0}' exited with code '{1}'.", 14 | "PSLIB_Required0": "Required: {0}", 15 | "PSLIB_StringFormatFailed": "String format failed.", 16 | "PSLIB_StringResourceKeyNotFound0": "String resource key not found: '{0}'", 17 | "PSLIB_TaskVariable0": "'{0}' task variable" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /variablerehydration-task/v0/rehydrate-variables-debug.ps1: -------------------------------------------------------------------------------- 1 | #Save-Module -Name VstsTaskSdk -Path ..\processtemplate-task\ps_modules\ 2 | 3 | 4 | #Import-Module ..\variablerehydration-task\ps_modules\VstsTaskSdk 5 | 6 | 7 | 8 | 9 | Invoke-VstsTaskScript -ScriptBlock ([scriptblock]::Create('. ..\variablerehydration-task\rehydrate-veriables.ps1')) -Verbose -------------------------------------------------------------------------------- /variablerehydration-task/v0/rehydrate-variables.ps1: -------------------------------------------------------------------------------- 1 | [CmdletBinding()] 2 | param( 3 | [string] $jsonfiles 4 | ) 5 | $jsonfiles = Get-VstsInput -Name jsonfiles -Require 6 | 7 | Write-VstsTaskVerbose "jsonfiles: $jsonfiles" 8 | 9 | $files = Get-ChildItem -Path $jsonfiles -Recurse 10 | 11 | Write-Output "Found $($files.count) files in $jsonfiles" 12 | 13 | if ($files.count -eq 0) 14 | { 15 | Write-VstsTaskError "There were no files found. You must specify at least one file to rehydrate. " 16 | Write-VstsSetResult -Result Failed -DoNotThrow 17 | exit 999 18 | } 19 | 20 | foreach ($file in $files) 21 | { 22 | Write-Output "Importing $file" 23 | Try 24 | { 25 | $results = Get-Content -Raw -Path $file | ConvertFrom-Json 26 | if ($results.Length -ne 0) 27 | { 28 | Write-Output $results 29 | foreach ($result in $results) 30 | { 31 | Write-Output "##vso[task.setvariable variable=$($result.Name);]$($result.Value)" 32 | } 33 | } 34 | else 35 | { 36 | Write-Output "No variables were found in $file" 37 | } 38 | } 39 | Catch 40 | { 41 | $ErrorMessage = $_.Exception.Message 42 | $FailedItem = $_.Exception.ItemName 43 | Write-VstsTaskError "Did not get a result retunred from the upload, twas not even JSON!" 44 | Write-VstsTaskError $ErrorMessage 45 | Write-VstsTaskError $result 46 | Write-VstsSetResult -Result Failed -DoNotThrow 47 | exit 666 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /variablerehydration-task/v0/task.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "7e7e1b5c-d87d-4a4c-a51a-95de28ce0fb9", 3 | "name": "variablerehydration", 4 | "friendlyName": "Variable Load Task", 5 | "description": "Loads the saved variables file and rehydrates the variables.", 6 | "helpMarkDown": "v#{GitVersion.FullSemVer}# [More Information](https://dev.azure.com/nkdagility/_git/Azure-DevOps-Variable-Tools?path=%2FREADME.md)", 7 | "category": "Utility", 8 | "visibility": [ 9 | "Build", 10 | "Deploy" 11 | ], 12 | "author": "naked Agility - Martin Hinshelwood", 13 | "version": { 14 | "Major": "#{GitVersion.Major}#", 15 | "Minor": "#{GitVersion.Minor}#", 16 | "Patch": "#{GitVersion.Patch}#" 17 | }, 18 | "minimumAgentVersion": "2.103.0", 19 | "groups": [ 20 | { 21 | "name": "missing", 22 | "displayName": "Missing variables", 23 | "isExpanded": true 24 | } 25 | ], 26 | "inputs": [ 27 | { 28 | "name": "jsonfiles", 29 | "type": "filePath", 30 | "label": "JSON Path", 31 | "defaultValue": "**\\meta-*.json", 32 | "required": true, 33 | "helpMarkDown": "Select the json file, or files to rehydrate." 34 | } 35 | ], 36 | "instanceNameFormat": "Load Build Variables $(jsonfiles)", 37 | "execution": { 38 | "PowerShell3": { 39 | "target": "$(currentDirectory)\\rehydrate-variables.ps1", 40 | "argumentFormat": "", 41 | "workingDirectory": "$(System.DefaultWorkingDirectory)" 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /vss-extension.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifestVersion": 1, 3 | "id": "variablehydration", 4 | "name": "Variable Tools for Azure DevOps Services", 5 | "version": "#{GitVersion.Major}#.#{GitVersion.Minor}#.#{GitVersion.Patch}#", 6 | "public": true, 7 | "publisher": "nkdAgility", 8 | "targets": [ 9 | { 10 | "id": "Microsoft.VisualStudio.Services.Cloud" 11 | }, 12 | { 13 | "id": "Microsoft.TeamFoundation.Server", 14 | "version": "[15.0,)" 15 | } 16 | ], 17 | "description": "Includes Build tasks to save (or dehydrate) you Azure Pipeline Build variables and Azure Pipeline Release tasks to help you load (or rehydrate) then in your Azure Pipeline Release process.", 18 | "categories": [ 19 | "Build and release" 20 | ], 21 | "tags": [ 22 | "release", 23 | "build", 24 | "variable" 25 | ], 26 | "links": { 27 | "learn": { 28 | "uri": "https://dev.azure.com/nkdagility/Azure-DevOps-Variable-Tools/_wiki/wikis/variable-tools" 29 | }, 30 | "support": { 31 | "uri": "https://github.com/nkdAgility/azure-devops-variable-tools/issues" 32 | } 33 | }, 34 | "repository": { 35 | "type": "git", 36 | "uri": "https://github.com/nkdAgility/azure-devops-variable-tools" 37 | }, 38 | "badges": [ 39 | { 40 | "href": "https://dev.azure.com/nkdagility/Azure-DevOps-Variable-Tools/_build?definitionId=99", 41 | "uri": "https://dev.azure.com/nkdagility/Azure-DevOps-Variable-Tools/_apis/build/status/CI", 42 | "description": "Azure Pipelines Build for the project" 43 | } 44 | ], 45 | "icons": { 46 | "default": "images/extension-icon.png" 47 | }, 48 | "branding": { 49 | "color": "#1C3272", 50 | "theme": "dark" 51 | }, 52 | "screenshots": [ 53 | { 54 | "path": "images/screenshot-01.png" 55 | } 56 | ], 57 | "content": { 58 | "details": { 59 | "path": "README.md" 60 | }, 61 | "license": { 62 | "path": "LICENSE.txt" 63 | } 64 | }, 65 | "files": [ 66 | { 67 | "path": "variablerehydration-task" 68 | }, 69 | { 70 | "path": "variabledehydration-task" 71 | } 72 | ], 73 | "contributions": [ 74 | { 75 | "id": "variablerehydration-task", 76 | "type": "ms.vss-distributed-task.task", 77 | "targets": [ 78 | "ms.vss-distributed-task.tasks" 79 | ], 80 | "properties": { 81 | "name": "variablerehydration-task" 82 | } 83 | }, 84 | { 85 | "id": "variabledehydration-task", 86 | "type": "ms.vss-distributed-task.task", 87 | "targets": [ 88 | "ms.vss-distributed-task.tasks" 89 | ], 90 | "properties": { 91 | "name": "variabledehydration-task" 92 | } 93 | } 94 | ] 95 | } --------------------------------------------------------------------------------