参数化powershell脚本通过SSIS执行进程任务(使用UNC)

时间:2017-05-04 10:56:35

标签: sql-server powershell ssis

我已经对如何从SSIS运行参数化PS脚本进行了大量研究。我在运行参数化脚本时遇到问题。 PS脚本如下,如果我将参数硬编码到脚本中,它的行为符合预期:

Param ([string]$filepath,[string]$filename)

$Path = $filepath
$InputFile = (Join-Path $Path $filename)
$Reader = New-Object System.IO.StreamReader($InputFile)

While (($Line = $Reader.ReadLine()) -ne $null) {
    If ($Line -match 'FILE\|([^\|]+)') {
        $OutputFile = "$($matches[1]).txt"
    }
    Add-Content (Join-Path $Path $OutputFile) $Line
}

在SSIS执行进程任务中运行,我试图通过表达式构建Arguments命令,如下所示:

"-ExecutionPolicy ByPass -File " + @[User::vPSScriptLocation] + " " + @[User::vFilePath]+ " "+ @[User::vFileName]

评估表达式给出以下内容:

-ExecutionPolicy ByPass -File \\WorkDirectory\Script.ps1 \\transfer datafile.data

执行时,任务失败。 .ps1从工作目录中删除,SSIS提供以下错误代码:

Error: 0xC0029151 at Execute powershell script, Execute Process Task: In Executing "C:\Windows\System32\WindowsPowerShell\v1.0\PowerShell.exe" "-ExecutionPolicy ByPass -File \\WorkDirectory\Script.ps1 \\transfer datafile.data" at "", The process exit code was "-196608" while the expected was "0".

看起来它得到一个空字符串,它不应该?任何指针都赞赏。

2 个答案:

答案 0 :(得分:0)

如果您使用这样的param-block将脚本作为ps1-File运行,则执行调用应按名称命名参数:

"-ExecutionPolicy ByPass -File " + @[User::vPSScriptLocation] + " -filepath " + @[User::vFilePath]+ " -filename "+ @[User::vFileName]

如果您使用有效的文件路径和文件名,则应该这样做。

如果它不起作用,请尝试将您的脚本编写为函数并在powershell-console中尝试。您的脚本作为函数如下所示:

function SearchLines
{
  Param (
    [string]$filepath,
    [string]$filename
  )
  $Path = $filepath
  $InputFile = (Join-Path $Path $filename)
  $Reader = New-Object System.IO.StreamReader($InputFile)
  While (($Line = $Reader.ReadLine()) -ne $null) {
     If ($Line -match 'FILE\|([^\|]+)') {
        $OutputFile = "$($matches[1]).txt"
    }
    Add-Content (Join-Path $Path $OutputFile) $Line
  }
}

用法:

SearchLines -filepath "\\your\unc\path\here" -filename "filename.txt"

如果这对您不起作用,请告诉我们您遇到的错误。

THX。

更新

根据您的评论,我希望您的功能写得很新,它尽可能地满足您的要求。该功能现在看起来像这样:

function SearchLines
{
  Param (
    [string]$InputFile
  )
  $FileContent = Get-Content $InputFile
  foreach($Line in $FileContent)
  {
    If ($Line -match 'FILE\|([^\|]+)') 
    {
       $OutputFile = "$($matches[1]).txt"
    }    
  Add-Content -Path $OutputFile -Value $Line
  }
}

用法:

SearchLines -InputFile c:\your\path\to\your\file.log

此函数为给定文件中的每一行创建一个名为行中写入内容的实际文件夹中的新文件。 Cmdlet Join-Path只是将两个字符串加在一起,而不检查其合理性。这就是为什么你可以简单地提交文件的完整路径而不是单独的参数中的路径和文件。

如果您需要输入文件的路径来为输出文件设置它,您可以使用以下行来获取它:

$tmpPath = Get-Childitem $InputFullPath
$Path = $tmpPath.Directory.FullName

因为你没有解释这个脚本到底应该做什么,所以我希望你能用它来得到你想要的东西。

问候

答案 1 :(得分:0)

好的,因为看起来我无法使用执行流程任务调用UNC路径来执行此操作,我决定在脚本任务中执行此操作,并将参考添加到System.Management.Automation,这允许我创建PowerShell实例。这远非我理想的解决方案,因为我真的想调用.ps1文件,但看起来这是我唯一的解决方案,因为我需要使用UNC路径。

我使用我的Dts变量构建PS脚本,然后在实例中执行它,从而实现了所需的结果:

    public void Main()
    {
        string filepath = Dts.Variables["User::vUNCPath"].Value.ToString();
        string filename = Dts.Variables["User::vFileName"].Value.ToString();
        string searchterm = Dts.Variables["User::vSearchTerm"].Value.ToString();
        bool fireAgain = true;

        // Build powershell script
        string script = "$Path = \""+filepath+"\";"+
                        "$InputFile = (Join-Path $Path \""+ filename+"\");" +
                        "$Reader = New-Object System.IO.StreamReader($InputFile);" +
                         "While (($Line = $Reader.ReadLine()) -ne $null) {" +
                        "If ($Line -match '"+searchterm+"') { "+
                        "$OutputFile = \"$($matches[1]).txt\"};" + 
                        "Add-Content (Join-Path $Path $OutputFile) $Line}";

        Dts.Events.FireInformation(0, "Info", "Powershell script built: " + script, String.Empty, 0, ref fireAgain);

        try
        {
            // Create instance to run script
            using (PowerShell psinstance = PowerShell.Create())
            {
                //Assign built script to this instance
                psinstance.AddScript(script);

                //Run powershell script
                psinstance.Invoke();

            }

            Dts.TaskResult = (int)ScriptResults.Success;
        }
        catch (Exception ex)
        {
            Dts.Events.FireError(0, "Error", ex.Message, String.Empty, 0);
            Dts.TaskResult = (int)ScriptResults.Failure;
        }
    }