PowerShell invoke-sqlcmd Get-ChildItem:无法调用方法。提供者不支持使用过滤器

Fra*_*ohn 1 powershell invoke-sqlcmd

使用 invoke-sqlcmd 将行插入表时发生了一个奇怪的错误。如果执行一次,整个脚本可以完美运行,但是如果我第二次运行它,它会失败并显示错误消息:Get-ChildItem:无法调用方法。提供程序不支持使用过滤器。我测试了代码并注释掉了 invoke-sqlcmd 行,并且可以多次运行它而没有任何错误。我将 invoke-sqlcmd 放在一个函数中,但它仍然出错,并且在第一次成功运行后,它也会在 PS 命令行中失败。

Clear-Host
$ErrorActionPreference = 'Stop'

function Update-SQL
{
    invoke-sqlcmd -query $strSQLInsert -server SXLSV-LEAPDBD1 -database DTCS_DV
}

$files = Get-ChildItem '\\pcslog1011\dtcs\ContractEmailNotes\' -Filter '*.txt' | Where-Object {$_.LastWriteTime -ge '08/22/2016 00:00:00' -and $_.LastWriteTime -le '08/22/2016 23:59:59'} | sort-object -Descending

for ($i=0; $i -lt $files.Count; $i++) 
{
    $SNAC_CNTR_ID = $files[$i].BaseName.Substring(0,6)
    $SNAC_MODIFIED = '{0:yyyy-MM-dd HH:mm:ss}' -f ($files[$i].LastWriteTime)

    $reader = [System.IO.File]::OpenText($files[$i].FullName)
    $lineCnt = 0
    $SNAC_ACTION = ''
    for() 
    {
        $lineCnt += 1 
        $line = $reader.ReadLine()
        if ($line -eq $null) {break}
        if ($lineCnt -eq 4)
        {
            if ($line.Contains('AMENDED') -eq $True)
            {
                $SNAC_ACTION = 'AMENDED'
            }
            elseif ($line.Contains('DEAL CHANGED') -eq $True)
            {
                $SNAC_ACTION = 'CHANGED'
            }
            else
            {
                $SNAC_ACTION = 'NEW'
            }
        }
    }
    $reader.Close()

    write-host $SNAC_CNTR_ID $SNAC_MODIFIED $SNAC_ACTION

    $strSQLInsert = "INSERT INTO CQT_CONTRACT_SOX_NAC_LIST (SNAC_CNTR_ID, SNAC_MODIFIED, SNAC_ACTION, SNAC_UPDATED_BY, SNAC_UPDATED_ON) VALUES ('" + $SNAC_CNTR_ID + "', '" + $SNAC_MODIFIED + "', '" + $SNAC_ACTION + "', Default, Default)"

    Update-SQL $strSQLInsert
}

exit
Run Code Online (Sandbox Code Playgroud)

小智 5

我知道这是一个相当古老的线程,但我遇到了一个类似的问题,导致我进入了这个页面。以下是为我解释和解决问题的链接。

PowerShell Invoke-Sqlcmd 切换到 sqlps 会话
卡在 Powershell sqlserver 中

简答

默认情况下,SQLPS 提供程序不识别 UNC 路径。您可以使用特定的文件系统提供程序作为 UNC 路径的前缀:

Get-ChildItem Microsoft.PowerShell.Core\FileSystem::\\pcslog1011\dtcs\ContractEmailNotes\
-Filter '*.txt'
Run Code Online (Sandbox Code Playgroud)

或者在 SQLPS 模块加载后将您的工作目录切换回默认值,方法是将其添加到脚本的顶部:

Push-Location
Import-Module SQLPS -DisableNameChecking
Pop-Location
Run Code Online (Sandbox Code Playgroud)

长答案

问题似乎是由于 PowerShell 将工作目录从默认值切换到 SQLPS 提供程序的工作目录以及 SQLPS 提供程序无法识别 UNC 路径的组合(没有一些鼓励)。

因此,正常的 PowerShell 提示符如下所示:

PS C:\Users\foobar>
Run Code Online (Sandbox Code Playgroud)

这反而看起来像提示,当你在SQLPS供应商的目录结构如下工作(更多这意味着什么这里):

PS SQLSERVER:\>
Run Code Online (Sandbox Code Playgroud)

无论如何,脚本第一次调用 Get-ChildItem 时,很可能是从默认 PowerShell 工作目录的上下文中调用的(其中 UNC 路径可以理解)。但是,调用 Invoke-Sqlcmd 会加载 SQLPS 模块,该模块将工作目录更改为无法识别 UNC 路径的提供程序的工作目录。因此,下次调用 Get-ChildItem 时,它是从提供程序的目录结构中调用的,从而引发错误。该问题实际上与过滤器支持无关。

其他人发现的两种方法是在 UNC 路径前面加上文件系统提供程序,以便 SQLPS 可以解析它():

Get-ChildItem Microsoft.PowerShell.Core\FileSystem::\\pcslog1011\dtcs\ContractEmailNotes\ -Filter '*.txt'
Run Code Online (Sandbox Code Playgroud)

或者在 SQLPS 模块加载后切换回默认工作目录。这可能最好通过在脚本开头显式加载 SQLPS 提供程序并在前后添加 Push/Pop-Location cmdlet(不需要对原始脚本进行其他更改)来完成。

Push-Location
Import-Module SQLPS -DisableNameChecking
Pop-Location
Run Code Online (Sandbox Code Playgroud)

最后要注意两点。首先,我在大约 100 台不同操作系统版本、补丁级别和 PowerShell 版本的服务器上运行了我的代码。我只在一些运行 PowerShell 5.1 的服务器上看到过这个问题。其他 5.1 服务器没问题。

其次,这整个事件显然可以通过简单地使用应该替换 SQLPS 的较新的 SQLServer 提供程序来避免。