3

Powershell v3 を使用して Windows Server 2012 でアプリケーションの展開スクリプトをテストしています。スクリプトは、Win Server 2008 R2 および Powershell v2 を使用する Win 7 で正常に動作します。私が今直面している問題は、-ArgumentList 経由で渡された XML 変数のプロパティにアクセスできないことです。

私のメインスクリプトが行うSharePoint、IIS、その他のいずれも持たない単純なスクリプトで、Powershell v3を使用してWin 7およびWin Server 2012で問題を再現できました。

スクリプト(私は今見つけることができない同様の質問からこれを借りたと思います):

$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 構文も試しましたが、同じことを行います。

4

3 に答える 3

1

これを試して、ジョブを実行する PowerShell のバージョンを指定します。

Start-Job -ScriptBlock $ScriptBlock -ArgumentList $foobar -PSVersion 2.0
于 2013-03-22T20:48:30.153 に答える
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

探し続けて、見つけたものを見ていきます。

アップデート:

コマンドを使用して PS 2.0 でスクリプトを実行すると、次powershell -version 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

探し終わりました。深入りすると頭が痛くなる。

于 2013-03-22T20:49:05.140 に答える
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 つのジョブが生成され、1 つのラップされた 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
于 2013-06-26T06:01:36.540 に答える