【问题标题】:Parameterised powershell script through SSIS Execute Process Task (with UNC)通过 SSIS 执行进程任务(使用 UNC)参数化的 powershell 脚本
【发布时间】:2017-05-05 19:21:21
【问题描述】:

我对如何从 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".

看起来它在不应该的地方得到了一个空字符串?任何指针表示赞赏。

【问题讨论】:

  • 所以你的进程应该读取文件“\\transfer\datafile.data”?这不是有效的 UNC 路径。如果您运行错误中显示的代码,您的脚本是否有效?它看起来也将所有参数作为一个字符串传递,但这可能只是错误的编写方式。必须检查 -File 是否支持 UNC。 This question 在尝试使用文件的 UNC 路径时出错。
  • 它应该读取 \\WorkDirectory\Script.ps1,这又不是 UNC。我也尝试在语音标记中传递参数,但得到相同的结果。它可能是 UNC,尽管它从读取位置删除 ps1 文件是非常奇怪的行为。
  • "\\WorkDirectory\Script.ps1" 不是有效路径,因此我认为 powershell 不知道您要运行什么。那应该是相对路径还是什么?我敢打赌,您没有 PowerShell 正在寻找的名为 WorkDirectory 的服务器。同样的问题应该发生在 in 您的脚本中,这就是我在您构建无效的类似路径之前试图指出的问题
  • 它有一个正确的服务器名称,\\WorkDirectory 只是说明性的。就像我在原始问题中所说的那样,如果我在 PS ISE 中运行这个脚本,并为参数分配值,它就可以正常工作。我猜这是因为 SSIS 和 UNC 路径在此任务中缺乏兼容性。
  • 它有一个正确的服务器名称,\\WorkDirectory 只是说明性的。 好的。这很好,但您应该使用正确的命名示例。由于格式错误的路径可能是您问题的一部分,因此我专注于您问题的那一部分,即“\\Server\Scripts\Script.ps1”。你真正的路径中有空格吗?

标签: sql-server powershell ssis


【解决方案1】:

好的,因为看起来我无法使用执行进程任务调用 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;
        }
    }

【讨论】:

    【解决方案2】:

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

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

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

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

    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"
    

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

    谢谢。

    更新

    根据您的 cmets,我编写了您的新功能,希望它尽可能满足您的要求。该函数现在看起来像这样:

    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
    

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

    问候

    【讨论】:

    • 第一次尝试给出与原始问题相同的错误。控制台中的第二个返回以下内容,这可能是我对 powershell 缺乏了解......术语“SearchLines”未被识别为 cmdlet、函数、scr ipt 文件或可运行程序的名称。检查名称的拼写,如果包含路径,请验证路径是否正确,然后重试。
    • 在您尝试使用之前,将我的答案中的完整源代码复制并粘贴到 powershell 控制台中。如果您在脚本文件中使用它,您可以将其复制到脚本文件的开头,在参数块之后。
    • OK 使用你的它说明“异常调用“.ctor”与“1”参数:找不到文件“\\your\unc\path\here\-”“在第 9 行char 23 $Reader = 新对象
    • 错误消息说它找不到您的输入文件。也许 Join-path 的工作方式与您认为的不同。我现在正在回家的路上,稍后回复以获得更有用的答案。你的脚本首先应该做什么?
    • 我在我的解决方案中添加了一些 - 希望它适合您的需求
    猜你喜欢
    • 1970-01-01
    • 2015-02-16
    • 2019-09-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-11
    相关资源
    最近更新 更多