简体   繁体   中英

How to execute powershell script from FAKE - F#MAKE

I am migrating MSBuild code to FAKE - and I am not able to execute powershell script from fake ,below is the code of MSBuild file to be written in FAKE :

<Target Name="VersionConfig"> 
    <Exec IgnoreExitCode="false" LogStandardErrorAsError="true" StandardErrorImportance="high" Command="powershell -File &quot;$(BuildRoot)\DeployScripts\scripts\AdminScripts\VersionUpdateFile.ps1&quot;  -path &quot;$(BuildSolutionVersioningConfig)&quot; -majorVersion &quot;$(BuildNumberMajor)&quot; -minor &quot;$(BuildNumberMinor)&quot; -build &quot;$(BuildNumber)&quot; -revision &quot;$(BuildNumberRevision)&quot;"/>
</Target>

How to write this in FAKE , I'm new to FAKE and have not used F# much, so forgive me if this should be obvious.

If anyone can help , that would be really helpful.

Thank You .

You can create a Powershell pipeline in any .NET application with the classes of the System.Management.Automation namespace. You can use that pipeline to execute commands locally or on a remote machine.

The following target retrieves the list of processes and prints them. It's the F# equivalent of the documentation example for the PowerShell class:

Target "ProcTest" (fun _ ->
    PowerShell.Create()    
            .AddCommand("get-process")
            .Invoke()
            |> Seq.map(fun result->(  result.Properties.["ProcessName"].Value,
                                      result.Properties.["ID"].Value))
            |> Seq.iter (fun (name,id)->printfn "%-24O %O" name id)
)

The is a quick & dirty module I use to execute commands (specifically chocolatey commands) on a remote server. The only thing you need to make it work on the local machine is to remove the ComputerName parameter:

#r "System.Management.Automation"

module MyPowershell =

    let InvokeRemote server command =
        let block = ScriptBlock.Create(command)
        let pipe=PowerShell.Create()    
                .AddCommand("invoke-command")
        pipe.AddParameter("ComputerName", server)            
            .AddParameter("ScriptBlock", block)
            .Invoke() 
            |> Seq.map (sprintf  "%O")
            |> Seq.iter (fun line ->
                                let tracer=if line.Contains("not installed") then
                                                traceError 
                                        else 
                                                trace
                                tracer line)
        pipe.Streams.Error |> Seq.iter (traceError << sprintf "%O" )

The pipeline is represented by the PowerShell class. The steps to construct it are :

  1. Create a PowerShell pipeline with PowerShell.Create()
  2. Create a ScriptBlock with the command you want to execute. You don't need a ScriptBlock for all commands. In this case, ScriptBlock contains the script I want to execute remotely.
  3. Add what you want to execute. In my case, I want to run a single invoke-command command
  4. Add parameters. In this case, it's -ComputerName myServer and -ScriptBlock ... with the block to execute.
  5. Run the pipeline with PowerShell.Invoke()
  6. Parse the results for possible warning messages that didn't make it to the Error stream

PowerShell errors are sent to the Error stream, which makes error handling easier.

Executing a command on the local machine can be a lot simpler:

let InvokeRemote command =
    let pipe=PowerShell.Create()    
            .AddCommand(command)
    pipe.Invoke() 
        |> Seq.map (sprintf  "%O")
        |> Seq.iter (fun line ->
                            let tracer=if line.Contains("not installed") then
                                            traceError 
                                    else 
                                            trace
                            tracer line)
    pipe.Streams.Error |> Seq.iter (traceError << sprintf "%O" )

The Fake.ProcessHelper namespace in FAKE is what you're looking for. The documentation won't tell you this, but Fake.ProcessHelper is marked with the AutoOpen attribute , which means that all the functions listed in that API reference page I linked are available to you from your FAKE build script, without you needing any explicit open statements to use them. You use it like this:

let inQuotes s = sprintf "\"%s\"" s

Target "Sample" (fun _ ->
  let retCode =
    ExecProcess
      (fun info ->
        info.Name <- "powershell.exe"  // Don't know if you need full path here
        info.WorkingDirectory <- getBuildParam "BuildRoot"
        info.Arguments <-
          [ "-File"; getBuildParam "BuildRoot" + "\DeployScripts\scripts\AdminScripts\VersionUpdateFile.ps1" |> inQuotes;
            "-path"; getBuildParam "BuildSolutionVersioningConfig" |> inQuotes;
            "-majorVersion"; getBuildParam "BuildNumberMajor" |> inQuotes;
            "-minor"; getBuildParam "BuildNumberMinor" |> inQuotes;
            "-build"; getBuildParam "BuildNumber" |> inQuotes;
            "-revision"; getBuildParam "BuildNumberRevision" |> inQuotes
          ] |> separated " "
      )
      (TimeSpan.FromMinutes 5.0)
  if retCode <> 0 then
    failwith (sprintf "PowerShell exited with non-zero exit code %d" retCode)
)

A couple notes:

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM