@@ -244,6 +244,53 @@ pub fn nuget_command_step(command: impl Into<String>) -> TaskStep {
244244 TaskStep :: new ( "NuGetCommand@2" , format ! ( "NuGet {cmd}" ) ) . with_input ( "command" , cmd)
245245}
246246
247+ /// Returns a [`TaskStep`] for `PowerShell@2` in file-path mode.
248+ ///
249+ /// Runs the PowerShell script at `file_path` on Linux, macOS, or Windows.
250+ /// `file_path` must be a fully qualified path or relative to
251+ /// `$(System.DefaultWorkingDirectory)`.
252+ ///
253+ /// Optional inputs (applied via `.with_input(…)` on the returned value):
254+ ///
255+ /// | Input key | Type | Default | Description |
256+ /// |---|---|---|---|
257+ /// | `arguments` | string | — | Arguments passed to the script. |
258+ /// | `errorActionPreference` | string | `"stop"` | Non-terminating error behaviour: `"stop"`, `"continue"`, `"silentlyContinue"`. |
259+ /// | `failOnStderr` | bool string | `"false"` | Fail the step if anything is written to stderr. |
260+ /// | `ignoreLASTEXITCODE` | bool string | `"false"` | Do not fail when `$LASTEXITCODE` is non-zero. |
261+ /// | `pwsh` | bool string | `"false"` | Use PowerShell Core (`pwsh`) instead of Windows PowerShell. |
262+ /// | `workingDirectory` | string | — | Working directory for the script. |
263+ ///
264+ /// ADO task reference:
265+ /// <https://learn.microsoft.com/en-us/azure/devops/pipelines/tasks/reference/powershell-v2>
266+ pub fn powershell_file_step ( file_path : impl Into < String > ) -> TaskStep {
267+ TaskStep :: new ( "PowerShell@2" , "PowerShell Script" )
268+ . with_input ( "targetType" , "filePath" )
269+ . with_input ( "filePath" , file_path)
270+ }
271+
272+ /// Returns a [`TaskStep`] for `PowerShell@2` in inline mode.
273+ ///
274+ /// Runs `script` as an inline PowerShell block on Linux, macOS, or Windows.
275+ ///
276+ /// Optional inputs (applied via `.with_input(…)` on the returned value):
277+ ///
278+ /// | Input key | Type | Default | Description |
279+ /// |---|---|---|---|
280+ /// | `errorActionPreference` | string | `"stop"` | Non-terminating error behaviour: `"stop"`, `"continue"`, `"silentlyContinue"`. |
281+ /// | `failOnStderr` | bool string | `"false"` | Fail the step if anything is written to stderr. |
282+ /// | `ignoreLASTEXITCODE` | bool string | `"false"` | Do not fail when `$LASTEXITCODE` is non-zero. |
283+ /// | `pwsh` | bool string | `"false"` | Use PowerShell Core (`pwsh`) instead of Windows PowerShell. |
284+ /// | `workingDirectory` | string | — | Working directory for the script. |
285+ ///
286+ /// ADO task reference:
287+ /// <https://learn.microsoft.com/en-us/azure/devops/pipelines/tasks/reference/powershell-v2>
288+ pub fn powershell_inline_step ( script : impl Into < String > ) -> TaskStep {
289+ TaskStep :: new ( "PowerShell@2" , "PowerShell Script" )
290+ . with_input ( "targetType" , "inline" )
291+ . with_input ( "script" , script)
292+ }
293+
247294#[ cfg( test) ]
248295mod tests {
249296 use super :: * ;
@@ -682,4 +729,116 @@ mod tests {
682729 assert_eq ! ( t. inputs. get( "command" ) . map( |s| s. as_str( ) ) , Some ( * cmd) ) ;
683730 }
684731 }
732+
733+ // ── PowerShell@2 ─────────────────────────────────────────────────────
734+
735+ #[ test]
736+ fn powershell_file_step_sets_task_and_required_inputs ( ) {
737+ let t = powershell_file_step ( "scripts/deploy.ps1" ) ;
738+ assert_eq ! ( t. task, "PowerShell@2" ) ;
739+ assert_eq ! ( t. display_name, "PowerShell Script" ) ;
740+ assert_eq ! (
741+ t. inputs. get( "targetType" ) . map( |s| s. as_str( ) ) ,
742+ Some ( "filePath" )
743+ ) ;
744+ assert_eq ! (
745+ t. inputs. get( "filePath" ) . map( |s| s. as_str( ) ) ,
746+ Some ( "scripts/deploy.ps1" )
747+ ) ;
748+ // only the required inputs are set by default
749+ assert_eq ! ( t. inputs. len( ) , 2 ) ;
750+ }
751+
752+ #[ test]
753+ fn powershell_file_step_accepts_optional_arguments ( ) {
754+ let t = powershell_file_step ( "$(System.DefaultWorkingDirectory)/scripts/build.ps1" )
755+ . with_input ( "arguments" , "-Configuration Release -OutputDir $(Build.ArtifactStagingDirectory)" )
756+ . with_input ( "workingDirectory" , "$(Build.SourcesDirectory)" ) ;
757+ assert_eq ! ( t. task, "PowerShell@2" ) ;
758+ assert_eq ! (
759+ t. inputs. get( "filePath" ) . map( |s| s. as_str( ) ) ,
760+ Some ( "$(System.DefaultWorkingDirectory)/scripts/build.ps1" )
761+ ) ;
762+ assert_eq ! (
763+ t. inputs. get( "arguments" ) . map( |s| s. as_str( ) ) ,
764+ Some ( "-Configuration Release -OutputDir $(Build.ArtifactStagingDirectory)" )
765+ ) ;
766+ assert_eq ! (
767+ t. inputs. get( "workingDirectory" ) . map( |s| s. as_str( ) ) ,
768+ Some ( "$(Build.SourcesDirectory)" )
769+ ) ;
770+ assert_eq ! ( t. inputs. len( ) , 4 ) ;
771+ }
772+
773+ #[ test]
774+ fn powershell_file_step_accepts_error_and_exit_flags ( ) {
775+ let t = powershell_file_step ( "scripts/test.ps1" )
776+ . with_input ( "errorActionPreference" , "continue" )
777+ . with_input ( "failOnStderr" , "true" )
778+ . with_input ( "ignoreLASTEXITCODE" , "true" )
779+ . with_input ( "pwsh" , "true" ) ;
780+ assert_eq ! ( t. task, "PowerShell@2" ) ;
781+ assert_eq ! (
782+ t. inputs. get( "errorActionPreference" ) . map( |s| s. as_str( ) ) ,
783+ Some ( "continue" )
784+ ) ;
785+ assert_eq ! (
786+ t. inputs. get( "failOnStderr" ) . map( |s| s. as_str( ) ) ,
787+ Some ( "true" )
788+ ) ;
789+ assert_eq ! (
790+ t. inputs. get( "ignoreLASTEXITCODE" ) . map( |s| s. as_str( ) ) ,
791+ Some ( "true" )
792+ ) ;
793+ assert_eq ! ( t. inputs. get( "pwsh" ) . map( |s| s. as_str( ) ) , Some ( "true" ) ) ;
794+ assert_eq ! ( t. inputs. len( ) , 6 ) ;
795+ }
796+
797+ #[ test]
798+ fn powershell_inline_step_sets_task_and_required_inputs ( ) {
799+ let script = "Write-Host 'Hello, World!'" ;
800+ let t = powershell_inline_step ( script) ;
801+ assert_eq ! ( t. task, "PowerShell@2" ) ;
802+ assert_eq ! ( t. display_name, "PowerShell Script" ) ;
803+ assert_eq ! (
804+ t. inputs. get( "targetType" ) . map( |s| s. as_str( ) ) ,
805+ Some ( "inline" )
806+ ) ;
807+ assert_eq ! (
808+ t. inputs. get( "script" ) . map( |s| s. as_str( ) ) ,
809+ Some ( "Write-Host 'Hello, World!'" )
810+ ) ;
811+ // only the required inputs are set by default
812+ assert_eq ! ( t. inputs. len( ) , 2 ) ;
813+ }
814+
815+ #[ test]
816+ fn powershell_inline_step_accepts_optional_flags ( ) {
817+ let t = powershell_inline_step ( "Get-Date" )
818+ . with_input ( "pwsh" , "true" )
819+ . with_input ( "errorActionPreference" , "silentlyContinue" )
820+ . with_input ( "workingDirectory" , "$(Build.SourcesDirectory)" ) ;
821+ assert_eq ! ( t. task, "PowerShell@2" ) ;
822+ assert_eq ! ( t. inputs. get( "pwsh" ) . map( |s| s. as_str( ) ) , Some ( "true" ) ) ;
823+ assert_eq ! (
824+ t. inputs. get( "errorActionPreference" ) . map( |s| s. as_str( ) ) ,
825+ Some ( "silentlyContinue" )
826+ ) ;
827+ assert_eq ! (
828+ t. inputs. get( "workingDirectory" ) . map( |s| s. as_str( ) ) ,
829+ Some ( "$(Build.SourcesDirectory)" )
830+ ) ;
831+ assert_eq ! ( t. inputs. len( ) , 5 ) ;
832+ }
833+
834+ #[ test]
835+ fn powershell_inline_step_multiline_script ( ) {
836+ let script = "$version = Get-Content VERSION\n Write-Host \" Building version $version\" " ;
837+ let t = powershell_inline_step ( script) ;
838+ assert_eq ! ( t. task, "PowerShell@2" ) ;
839+ assert_eq ! (
840+ t. inputs. get( "script" ) . map( |s| s. as_str( ) ) ,
841+ Some ( "$version = Get-Content VERSION\n Write-Host \" Building version $version\" " )
842+ ) ;
843+ }
685844}
0 commit comments