I run a dedicated server for an alpha/early access game called Space Engineers, occasionally they patch and break things and i am trying to create a powershell script to trouble shoot problems that may occur. I am ok with powershell, never messed with XML.
The first step is disabling all objects in the game so that they cause less calculations on the server. like so ->
$power = Get-Content 'F:\DedicatedServer\DataDir\SE Survival 2\Saves\VPS RC 1\SANDBOX_0_0_0_.sbs' -raw
$power = $power -replace "<Enabled>true</Enabled>", "<Enabled>false</Enabled>"
$power | Out-File 'F:\DedicatedServer\DataDir\SE Survival 2\Saves\VPS RC 1\SANDBOX_0_0_0_.sbs' -Encoding ascii
The second and third steps will be to bring all medical rooms and power sources (not shown) online. This is where i get into trouble.
[xml]$myXML = Get-Content 'F:\DedicatedServer\DataDir\SE Survival 2\Saves\VPS RC 1\SANDBOX_0_0_0_.sbs'
$ns = New-Object System.Xml.XmlNamespaceManager($myXML.NameTable)
$ns.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance")
$node = $myXML.SelectNodes('//SectorObjects/MyObjectBuilder_EntityBase/CubeBlocks/MyObjectBuilder_CubeBlock[@xsi:type="MyObjectBuilder_MedicalRoom"]/Enabled', $ns) | % {
#set all med bays to be enabled.
$switch= Select-XML -XML $myXML -XPath $node
$switch.Node.InnerText = $switch.Node.InnerText.Replace("false", "true")
$myXML.Save('F:\DedicatedServer\DataDir\SE Survival 2\Saves\VPS RC 1\SANDBOX_0_0_0_.sbs')
}
Here is an excerpt of the XML file with non relevant data removed -
<?xml version="1.0"?>
<MyObjectBuilder_Sector xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Position>
</Position>
<SectorEvents>
</SectorEvents>
<AppVersion>1044014</AppVersion>
<SectorObjects>
<MyObjectBuilder_EntityBase xsi:type="MyObjectBuilder_CubeGrid">
<EntityId>72230476941025901</EntityId>
<PersistentFlags>CastShadows InScene</PersistentFlags>
<PositionAndOrientation>
</PositionAndOrientation>
<GridSizeEnum>Large</GridSizeEnum>
<CubeBlocks>
<MyObjectBuilder_CubeBlock xsi:type="MyObjectBuilder_CubeBlock">
</MyObjectBuilder_CubeBlock>
<MyObjectBuilder_CubeBlock xsi:type="MyObjectBuilder_MedicalRoom">
<SubtypeName>LargeMedicalRoom</SubtypeName>
<EntityId>72107097601717796</EntityId>
<Min x="4" y="1" z="-1" />
<BlockOrientation Forward="Forward" Up="Up" />
<ColorMaskHSV x="0" y="0.15" z="0.25" />
<Owner>144233151425053409</Owner>
<ShareMode>Faction</ShareMode>
<CustomName>Lurch Enterprises</CustomName>
<ShowOnHUD>false</ShowOnHUD>
<Enabled>false</Enabled>
<SteamUserId>0</SteamUserId>
</MyObjectBuilder_CubeBlock>
the XML file is not updating with the desired changes. Which are change every instance of
<MyObjectBuilder_CubeBlock xsi:type="MyObjectBuilder_MedicalRoom">
<Enabled>false</Enabled>
to true.
The current errors are:
Select-Xml : Cannot validate argument on parameter 'XPath'. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
At line:16 char:44
+ $switch= Select-XML -XML $myXML -XPath $node
+ ~~~~~
+ CategoryInfo : InvalidData: (:) [Select-Xml], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.SelectXmlCommand
You cannot call a method on a null-valued expression.
At line:17 char:5
+ $switch.Node.InnerText = $switch.Node.InnerText.Replace("false", "true")
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
and answered! here is the final product that does what i wanted.
$filePath = '<your save file path here>\SANDBOX_0_0_0_.sbs'
#troubleshooting script
#switch EVERYTHING off
$power = Get-Content $filePath -raw
$power = $power -replace "<Enabled>true</Enabled>", "<Enabled>false</Enabled>"
$power | Out-File $filePath -Encoding ascii
#turn on medbays, reactors, batteries, solar panels ONLY
[xml]$myXML = Get-Content $filePath
$ns = New-Object System.Xml.XmlNamespaceManager($myXML.NameTable)
$ns.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance")
$nodes = $myXML.SelectNodes("//SectorObjects/MyObjectBuilder_EntityBase/CubeBlocks/MyObjectBuilder_CubeBlock[@xsi:type='MyObjectBuilder_MedicalRoom']/Enabled|//SectorObjects/MyObjectBuilder_EntityBase/CubeBlocks/MyObjectBuilder_CubeBlock[@xsi:type='MyObjectBuilder_Reactor']/Enabled|//SectorObjects/MyObjectBuilder_EntityBase/CubeBlocks/MyObjectBuilder_CubeBlock[@xsi:type='MyObjectBuilder_BatteryBlock']/Enabled|//SectorObjects/MyObjectBuilder_EntityBase/CubeBlocks/MyObjectBuilder_CubeBlock[@xsi:type='MyObjectBuilder_SolarPanel']/Enabled", $ns)
ForEach($node in $nodes)
{
$node.InnerText = "true"
}
$myXML.Save($filePath)
To be able to use xsi
prefix in your XPath you need to register prefix-to-namespace URI mapping to XmlNamespaceManager
, then pass the XmlNamespaceManager
to SelectNodes()
method :
.....
$ns = New-Object System.Xml.XmlNamespaceManager($myXML.NameTable)
$ns.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance")
$node = $myXML.SelectNodes("your xpath that contains xsi prefix here", $ns)
.....
UPDATE :
Turned out there was hidden character before [
in your XPath that's why you got "invalid token" error. I'm not familiar with PowerShell specific syntax, but this worked fine for me :
[xml]$myXML = Get-Content "F:\DedicatedServer\DataDir\SE Survival 2\Saves\VPS RC 1\SANDBOX_0_0_0_.sbs"
$ns = New-Object System.Xml.XmlNamespaceManager($myXML.NameTable)
$ns.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance")
$nodes = $myXML.SelectNodes("//SectorObjects/MyObjectBuilder_EntityBase/CubeBlocks/MyObjectBuilder_CubeBlock[@xsi:type='MyObjectBuilder_MedicalRoom']/Enabled", $ns)
ForEach($node in $nodes)
{
$node.InnerText = "true"
}
$myXML.Save("F:\DedicatedServer\DataDir\SE Survival 2\Saves\VPS RC 1\SANDBOX_0_0_0_.sbs")