为什么我通过 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] 实际上包含您可以使用的结果。
我在 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] 实际上包含您可以使用的结果。