为什么我通过 Start-Job 执行的 SQL 没有返回我期望的答案?

Why is my SQL executed via Start-Job not returning the answer I expect?

我在 SQL Server 2008 上托管了一个数据库,我的普通用户帐户无法访问该数据库。为了查询它,我需要使用我的特殊 "admin" 帐户(只是另一个 AD 帐户,但与我的普通用户帐户在不同的组中)。

我想出了一个想法,通过 Start-Job 在 Powershell 中使用后台作业来 运行 查询此数据库,因为您可以使用与登录用户不同的凭据启动作业,从而集成数据库的安全性正常工作。自从我的问题以来,今天下午我在谷歌上搜索了很多东西,看到一些人出于同样的原因采用了这种方法,但他们的结果似乎确实有效——而我的却不是出于某种原因。

我有以下 powershell 代码:

[scriptblock]$sql_block = {
    $Query = "select * from some_table"
    $CW_DBConnection = New-Object Data.SqlClient.SQLConnection
    $CW_DBConnection.ConnectionString = "Data Source=someserver;Initial Catalog=some_database;Integrated Security=SSPI;"
    $CW_DBConnection.Open()

    $Command = New-Object Data.SqlClient.SqlCommand($Query,$CW_DBConnection)
    $Adapter = New-Object Data.SqlClient.SqlDataAdapter
    $DataSet = New-Object Data.DataSet

    $Adapter.SelectCommand = $Command
    [void]$Adapter.Fill($DataSet)

    $CW_DBConnection.Close()

    return $DataSet
}

我通过以下方式执行:

$mySQLJob = Start-Job -ScriptBlock $sql_block -Credential $(Get-Credential -UserName AD\MyAdminAccount -Message "Enter Admin Password")
Wait-Job $mySQLJob
$results = Receive-Job $mySQLJob

一切顺利。然而,当我开始询问结果对象时,我看到了这个:

$results
RunspaceId              : 975030ec-d336-4583-9260-48439bb34292
RemotingFormat          : Xml
SchemaSerializationMode : IncludeSchema
CaseSensitive           : False
DefaultViewManager      : {System.Data.DataViewManagerListItemTypeDescriptor}
EnforceConstraints      : True
DataSetName             : NewDataSet
Namespace               :
Prefix                  :
ExtendedProperties      : {}
HasErrors               : False
IsInitialized           : True
Locale                  : en-GB
Site                    :
Relations               : {}
Tables                  : {System.Data.DataRow}
Container               :
DesignMode              : False
ContainsListCollection  : True

当我尝试进入表格位时:

$results.Tables[0]
System.Data.DataRow

$results.Tables[0].GetType()
IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     ArrayList                                System.Object

$results.Tables[0][0]
System.Data.DataRow

$results.Tables[0][0].GetType()
IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     String                                   System.Object

从字面上看,结果就是字符串 "System.Data.DataRow".

我哪里翘起来了?

注意 - 运行从 powershell 会话中执行此操作实际上作为我的管理员 ID 执行,而不是通过 Start-Job 执行此操作(即仅内联执行 SQL 位)按预期工作,并且我从数据库中获取实际数据。

当我发布这个问题时,我已经在 Can Powershell Receive-Job return a DataSet? 阅读了这个问题 - 但显然我没有足够仔细地阅读它 - 因为工作答案 return 不是顶级数据集对象,但是 Tables[0] 属性 就可以了。

我今天早上将我的脚本块更改为 return,瞧瞧,我现在得到了实际的 SQL 数据。

所以 Receive-Job 似乎没有将它 return 的对象序列化到足够的深度,以至于你可以 return 任意的(尽管我想你可以尝试自己序列化它们 -我还没试过。UPDATE:See 下面)。

所以,总结一下

的一行更改
return $DataSet

return $DataSet.Tables[0]

成功了。

更新:我现在已经尝试了 'serialize it yourself' 方法,这似乎工作正常。所以首先你更新脚本块以在最后执行此操作:

$Serialized_DataSet = [System.Management.Automation.PSSerializer]::Serialize($DataSet,2)
return $Serialized_DataSet

然后当您想要返回结果时:

$results = Receive-Job $mySQLJob
$deserialized_results = [System.Management.Automation.PSSerializer]::Deserialize($results)

然后您可以看到 $deserialized_results.Tables[0] 实际上包含您可以使用的结果。