我正在使用Powershell v3在Windows Server 2012上测试我的应用程序的部署脚本。该脚本在Win Server 2008 R2和Win 7上使用Powershell v2运行正常。我现在遇到的问题是我无法访问通过-ArgumentList传递的XML变量的属性。
我已经能够在一个简单的脚本中使用Powershell v3在Win 7和Win Server 2012上重现该问题,该脚本没有我的主脚本所做的任何SharePoint,IIS,misc。
脚本(我想我从一个我现在找不到的类似问题中借用了这个):
$xml = [xml] (Get-Content (Get-Item (".\input.xml")))
$foobar = $xml.Stuff.FooBars.Foobar
$ScriptBlock = {
$foobar = $args[0]
write-host "Inside the job..."
write-host ("Foobar : "+$foobar)
write-host ("Foobar.Foo : "+$foobar.Foo)
}
write-host "Outside the job..."
write-host ("Foobar: "+$foobar)
write-host ("Foobar.Foo : "+$foobar.Foo)
Start-Job -ScriptBlock $ScriptBlock -ArgumentList $foobar | Out-Null
While (Get-Job -State "Running") { Start-Sleep 2 }
write-host ("Jobs Completed.")
Get-Job | Receive-Job
Remove-Job *
输入XML:
<?xml version="1.0"?>
<Stuff xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<FooBars>
<FooBar>
<Foo>ThisIsAFoo</Foo>
<Bar>ThisIsABar</Bar>
</FooBar>
</FooBars>
</Stuff>
Powershell v2的输出:
PS C:\Powershell3Issues> .\demo.ps1
Outside the job...
Foobar: System.Xml.XmlElement
Foobar.Foo : ThisIsAFoo
Jobs Completed.
Inside the job...
Foobar : System.Collections.ArrayList System.Collections.ArrayList
Foobar.Foo : ThisIsAFoo
Powershell v3的输出:
PS C:\Powershell3Issues> .\demo.ps1
Outside the job...
Foobar: System.Xml.XmlElement
Foobar.Foo : ThisIsAFoo
Jobs Completed.
Inside the job...
Foobar : System.Collections.ArrayList System.Collections.ArrayList
Foobar.Foo :
注意缺少的Foobar.Foo值。
我也尝试过v3中的$ using语法,但它也做了同样的事情。
答案 0 :(得分:1)
尝试此操作以指定在以下位置运行作业的PowerShell版本:
Start-Job -ScriptBlock $ScriptBlock -ArgumentList $foobar -PSVersion 2.0
答案 1 :(得分:1)
我正在使用PS 3.0,它确实改变了数据类型。我修改了你的脚本来看看:
$xml = [xml] (Get-Content .\input.xml)
$foobar = $xml.Stuff.FooBars.Foobar
"Foobar Outside type = $($foobar.Gettype())"
$ScriptBlock = {
$foobar = $args[0]
"Foobar Inside type = $($foobar.Gettype())"
}
Start-Job -ScriptBlock $ScriptBlock -ArgumentList $foobar | Out-Null
While (Get-Job -State "Running") { Start-Sleep 2 }
Get-Job | Receive-Job
我得到的输出是:
Foobar Outside type = System.Xml.XmlElement
Foobar Inside type = System.Collections.ArrayList System.Collections.ArrayList
我会一直看着,看看我发现了什么。
<强>更新强>
当我使用命令powershell -version 2.0
在PS 2.0中运行脚本时,我收到错误消息:
Method invocation failed because [Deserialized.System.Xml.XmlElement] doesn't contain a method named 'Gettype'.
+ CategoryInfo : InvalidOperation: (Gettype:String) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound
+ PSComputerName : localhost
它从System.Xml.XmlElement更改为Deserialized.System.Xml.XmlElement,对吗?我会继续看,看看我发现了什么。
解决方法:强>
解决方法可能是传递一个对象而不是传递一个字符串。
$xml_path = 'C:\input.xml'
$sb = {
$xml = [xml](Get-Content $args[0])
...
}
Start-Job -ScriptBlock $sb -Args $xml_path
我已经完成了搜索。当我深入研究事物时,我的头疼。
答案 2 :(得分:1)
问题是您正在尝试序列化XMLElement类型的对象,该对象不会序列化。解决方法是克隆XMLElement并将其包装在新的XMLDocument中。
cls
$XMLDocument = [xml]@"
<?xml version="1.0"?>
<Stuff xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<FooBars>
<FooBar>
<Foo>ThisIsAFoo1</Foo>
<Bar>ThisIsABar2</Bar>
</FooBar>
<FooBar>
<Foo>ThisIsAFoo2</Foo>
<Bar>ThisIsABar2</Bar>
</FooBar>
</FooBars>
</Stuff>
"@
Select-Xml -Xml $XMLDocument -XPath 'Stuff/FooBars/FooBar' | foreach {
$SelectedNode = $_.Node
#$SelectedNode is now of type System.Xml.XmlElement which does not serialise
#but System.Xml.XmlDocument will serialise so wrap a clone of $SelectedNode in a new XMLDocument
#then pass that as the argument
$SerializationWrapper = New-Object System.Xml.XmlDocument
$SerializationWrapper.AppendChild($SerializationWrapper.ImportNode($SelectedNode, $true)) | Out-Null
Start-Job -ScriptBlock {
param($xml)
Write-Output "Start Job"
'The type of deserialise object $xml is: ' + $xml.getType()
$sw = New-Object system.io.stringwriter
$writer = New-Object system.xml.xmltextwriter($sw)
$writer.Formatting = [System.xml.formatting]::Indented
$xml.WriteContentTo($writer)
$sw.ToString()
Write-Output "Finish Job"
Write-Output ""
} -ArgumentList $SerializationWrapper
}
Get-Job | Wait-Job | Receive-Job
从下面的输出可以看出,生成了2个作业,并传递了一个包装好的FooBar元素进行格式化。
Id Name PSJobTypeName State HasMoreData Location Command
-- ---- ------------- ----- ----------- -------- -------
520 Job520 BackgroundJob Running True localhost ...
522 Job522 BackgroundJob Running True localhost ...
Start Job
The type of deserialise object $xml is: xml
<FooBar>
<Foo>ThisIsAFoo1</Foo>
<Bar>ThisIsABar2</Bar>
</FooBar>
Finish Job
Start Job
The type of deserialise object $xml is: xml
<FooBar>
<Foo>ThisIsAFoo2</Foo>
<Bar>ThisIsABar2</Bar>
</FooBar>
Finish Job