Not able to Get the Last node of an xml node properly - powershell

I am having 2 diffrent xml file with. Currently im trying to get the Last xml node. In the 1st ouput im getting because empty or Null value since i have a commented line. Please help how to handle in this case.
#Below line Run firstfile.xml
$xmlfile = 'C:\Programs\MyTasks\TCPROD-29658\Test_1309\D_SimulationTest\firstfile.xml'
#Below line to Run secondfile.xml
#$xmlfile = 'C:\Programs\MyTasks\TCPROD-29658\Test_1309\D_SimulationTest\secondfile.xml'
$xmllastsitenode = [xml]::new()
$xmllastsitenode.Load($xmlFile)
$lastsite_id = $xmllastsitenode.fccconfig.fccdefaults.LastChild.id
write-host 'Print1'
write-host $lastsite_id
if (!$lastsite_id) { Write-Host "variable is null" }
if ($lastsite_id) { Write-Host "variable is NOT null" }
write-host 'Print2'
Below is the xml files im trying to run
1st XML file
<?xml version="1.0" encoding="UTF-8"?>
<fccconfig version="1.3.2">
<fccdefaults>
<property name="CacheLocation" value="C:/Users/Public/" overridable="true"/>
<site id="-1940805554" overridable="true">
<parentfsc address="http://abcdefgh:1234/" priority="0" />
</site>
<!--__ANT_MARK__-->
</fccdefaults>
<!-- default parentfsc - this is a marker that will be overwritten by the installer -->
<parentfsc address="xyzlmnopq:10010" priority="0" transport="lan"/>
</fccconfig>
Output:-
Print1
variable is null
Print2
2nd XML file
<?xml version="1.0" encoding="UTF-8"?>
<fccconfig version="1.3.2">
<fccdefaults>
<property name="CacheLocation" value="C:/Users/Public/" overridable="true"/>
<site id="-1940805554" overridable="true">
<parentfsc address="http://abcdefgh:1234/" priority="0" />
</site>
</fccdefaults>
<!-- default parentfsc - this is a marker that will be overwritten by the installer -->
<parentfsc address="xyzlmnopq:10010" priority="0" transport="lan"/>
</fccconfig>
Output:-
Print1
-1940805554
variable is NOT null
Print2
Latest Code which have tried meantime
#Below line Run firstfile.xml
$xmlfile = 'C:\Programs\MyTasks\TCPROD-29658\Test_1309\D_SimulationTest\firstfile.xml'
#Below line to Run secondfile.xml
#$xmlfile = 'C:\Programs\MyTasks\TCPROD-29658\Test_1309\D_SimulationTest\secondfile.xml'
$xmllastsitenode = [xml]::new()
$xmllastsitenode.Load($xmlFile)
$lastsite_id = $xmllastsitenode.fccconfig.fccdefaults.LastChild.id
write-host 'Print1'
write-host $lastsite_id
if (!$lastsite_id)
{
Write-Host "variable is null"
# New logic to handle firt xml file cases
#$somesitetag ---> Having some xml tag content here
$newSiteNode = $xmlcontent.ImportNode($somesitetag, $true)
$antmarkline = (Get-Content $xmlfile) | select-string -Pattern $antmark
$xmlcontent.fccconfig.fccdefaults.InsertAfter($newSiteNode,$antmarkline)
}
if ($lastsite_id)
{
Write-Host "variable is NOT null"
#Insterting some new nodes
#This Working as second file conetent works here
}
write-host 'Print2'

You need to ignore the comments. Check the output of this for the first XML file.
$settings = [System.Xml.XmlReaderSettings]::new()
$settings.IgnoreComments = $true
$xmlreader = [System.Xml.XmlReader]::Create('./Desktop/Test.xml', $settings)
$xmldoc = [System.Xml.XmlDocument]::new()
$xmldoc.Load($xmlreader)
$xmldoc.fccconfig.fccdefaults.LastChild

Related

pass json as parameter in power shell script

I have made a function for creating new xml node.there are two parameters in my function on is a existing xml file reference and second one is element value.while running the script its showing an error
code
function createProviderNode($xmlData,$propertyValue){
Write-Host 'inside createProviderNode'
Write-Host ($propertyValue)
#[xml]$xmlData = get-content E:\powershell\data.xml
$newProviderNode = $xmlData.CreateNode("element","provider","")
$newProviderNode.SetAttribute("name",$propertyValue)
$xmlData.SelectSingleNode('providers').AppendChild($newProviderNode)
$xmlData.save("E:\powershell\data.xml")
}
did i miss anything in this code?
The error message implies that while you expected $xmlData to contain an object of type [xml] (System.Xml.XmlDocument) - i.e., an XML document - in reality it was a string ([string]).
In other words: When you called your createProviderNode function, the 1st argument you passed was a string, not an XML document (of type [xml]).
Typing your $xmlData parameter variable as [xml] solves this problem, as that will implicitly covert even a string argument to an XML document on demand - if possible.
A simplified example, using a script block in lieu of a function:
$xmlString = #'
<?xml version="1.0"?><catalog><book id="bk101"><title>De Profundis</title></book></catalog>
'#
# Note how $xmlData is [xml]-typed.
& { param([xml] $xmlData) $xmlData.catalog.book.title } $xmlString
The above yields De Profundis, demonstrating that the string argument was converted to an [xml] instance (which - thanks to PowerShell's type adaptation magic - makes the element names available as direct properties).
It is then safe to call the .CreateNode() method on $xmlData.
Well, you don't show your original XML format.
Why did you comment out that Get-Content? it will not work without it.
So, if we take the below example, it works as expected.
# Simple XML version
$SimpleXml = $null
$SimpleXml = #"
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<name>Apple</name>
<size>1234</size>
</configuration>
"#
# New node code
[xml]$XmlDoc = Get-Content -Path variable:\SimpleXml
$runtime = $XmlDoc.CreateNode("element","runtime","")
$generated = $XmlDoc.CreateNode("element","generatePublisherEvidence","")
$generated.SetAttribute("enabled","false")
$runtime.AppendChild($generated)
$XmlDoc.configuration.AppendChild($runtime)
$XmlDoc.save("$pwd\SimpleXml.xml")
Get-Content -Path "$pwd\SimpleXml.xml"
# Which creates this:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<name>Apple</name>
<size>1234</size>
<runtime>
<generatePublisherEvidence enabled="false" />
</runtime>
</configuration>
Also Write-Host is never needed unless you are coloring screen output.
Write-Output is the default and automatically write to the screen, whether you specify Write-Output or not.
So, all of these to the same thing - output to the screen.
$SomeString = 'hello'
Write-Host $SomeString
Write-Output $SomeString
'hello'
"hello"
$SomeString
"$SomeString"
($SomeString)
("$SomeString")
$($SomeString)
# Results
hello
hello
hello
hello
hello
hello
hello
… yet, it's your choice.

Parsing XML and ignoring sections with powershell

I want to parse out the key fields and Data table information from here with PowerShell.
I only want the datatable name if there is a keyfield so in the example below I do not want CC:Attribute.
I also want to output things to a text file.
I want to have a text file that is created that holds the Data table name & Access as well as all the key fields and what they are.
This is the code I have so far:
[xml]$global:xmldata = get-content "C:\hackathon\Mfg.xml"
$xmldata2 = $xmldata.SchemaPackage.Tables
$SField = $xmldata2.DataTable.KeyFields | %{$_.StringField}
$Reffield = $xmldata2.DataTable.KeyFields | %{$_.ReferenceField}
$table = $xmldata2 | %{$_.DataTable}
Xml File:
<?xml version="1.0" encoding="utf-8"?>
<SchemaPackage Namespace="Mfg" xmlns="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<DataTable Name="CC::Attribute">
<DataFields>
</DataFields>
</DataTable>
<DataTable Name="PlannerCode" Access="WW">
<Licenses>Manufacturing, DemandManagement</Licenses>
<Flags>
</Flags>
<KeyFields>
<StringField Name="Value"/>
<ReferenceField Name="Site" Target="Core::Site" SetField="PlannerCodes"/>
</KeyFields>
<DataFields>
<StringField Name="Description"/>
</DataFields>
</DataTable>
</SchemaPackage>
Despite the edit you made, I can only get your XML to validate if I modify it slightly (cleaning the opening XML tag and removing the SchemaPackage namespace). Regardless,
if you're experiencing no issues with your XML import then it's fine.
Here I'm just constructing the XML object from a herestring because I haven't got it in a file on disk.
[xml]$xmldata = #"
<xml>
<DataTable Name="CC::Attribute">
<DataFields>
</DataFields>
</DataTable>
<DataTable Name="PlannerCode">
<Licenses>Manufacturing, DemandManagement</Licenses>
<Flags>
</Flags>
<KeyFields>
<StringField Name="Value"/>
<ReferenceField Name="Site" Target="Core::Site" SetField="PlannerCodes"/>
</KeyFields>
<DataFields>
<StringField Name="Description"/>
</DataFields>
</DataTable>
</xml>
"#
# Filter DataTable nodes for those with a KeyFields child node.
$DataTablesWithKeyFields = $xmldata.xml.DataTable | Where-Object { $_.KeyFields }
$DataTableName = $DataTablesWithKeyFields.Name
$StringFieldData = $DataTablesWithKeyFields.KeyFields.ReferenceField
$ReferenceFieldData = $DataTablesWithKeyFields.KeyFields.ReferenceField
I'm not sure if that's what you're after. $DataTablesWithKeyFields could be an array depending on your XML file so you may need to loop it to extract the information you require.
Since we're working with XML, one of the querying options is XPath!
You can select only DataTable nodes that have a KeyFields child with the following XPath expression:
/SchemaPackage/DataTable[KeyFields]
You can use Select-Xml:
Select-Xml -Path C:\hackathon\Mfg.xml -XPath /SchemaPackage/DataTable[KeyFields] |Select-Object -Expand Node
or pass the expression as an argument to the SelectSingleNodes() method:
[xml]$xmldata = Get-Content C:\hackathon\Mfg.xml
$xmldata.SelectNodes('/SchemaPackage/DataTable[KeyFields]')

Unable to update a value in msbuild proj file using powershell

I am trying to read a .csproj file using powershell by converting it into xml file to increment WPF app version value. I am able to read the value without any issue and incremented the version value but when I try to save the file with new value, the value doesn't get saved. The code I pasted in this question is to update the QA details.
I am trying to read the below file. How do i update and save file
<Choose>
<When Condition=" '$(BuildEnvironment)' == 'QA' ">
<PropertyGroup>
<ApplicationVersion>1.0.0.1</ApplicationVersion>
<PublishDirectory>C:\TestDirectory</PublishDirectory>
<InstallUrl>http://testurl/testapp</InstallUrl>
<ProductName>Test1.QA</ProductName>
<PublishAssemblyName>Test1.QA</PublishAssemblyName>
</PropertyGroup>
<ItemGroup>
<Tokens Include="ApplicationManifestFileName">
<ReplacementValue>Test1.QA.application</ReplacementValue>
<Visible>false</Visible>
</Tokens>
</ItemGroup>
</When>
<When Condition=" '$(BuildEnvironment)' == 'Production' ">
<PropertyGroup>
<ApplicationVersion>1.0.0.0</ApplicationVersion>
<PublishDirectory>C:\TestDirectory2</PublishDirectory>
<InstallUrl>http://test2url/test2app/</InstallUrl>
<ProductName>Test=2.Prod</ProductName>
<PublishAssemblyName>Test2.Prod</PublishAssemblyName>
</PropertyGroup>
<ItemGroup>
<Tokens Include="ApplicationManifestFileName">
<ReplacementValue>Tes2.Prod.application</ReplacementValue>
<Visible>false</Visible>
</Tokens>
</ItemGroup>
</When>
$Test1QAMSBuildFile = 'C:\Directory\Test.csproj'
[xml]$Test1QABuildVersion = Get-Content $Test1QAMSBuildFile
$CurrentQAVersion= $Test1QABuildVersion.Project.Choose.when.PropertyGroup | ? { $_.ProductName -eq 'Test1.QA' } | Select-Object -Property ApplicationVersion
$PropertyVersion= $CurrentQAVersion.ApplicationVersion
$UpdateVersion= $PropertyVersion.split(".")
$major= [int] ($Updateversion[0])
$minor= [int] ($Updateversion[1])
$patch= [int] ($Updateversion[2])
$revision=[int] ($Updateversion[3])
$newrevisionversion= $revision+1
$newVersion =( [string] $major )+ "."+ ( [string] $minor) +"."+ ([string]$patch ) +"."+ ([string]$newrevisionversion )
$UpdateVersion ="$newVersion"
$TestQABuildVersion.Save("Test1QAMSBuildFile")`
After I added the closing </Choose> I removed .Project from line 3, so you may need to alter what I give you to properly apply to your file.
You never updated $TestQABuildVersion, only some other things that referenced it. What you probably want to do is:
$Test1QAMSBuildFile = 'C:\Directory\Test.csproj'
[xml]$Test1QABuildVersion = Get-Content $Test1QAMSBuildFile
$PropertyVersion = $Test1QABuildVersion.Choose.when.PropertyGroup | ? { $_.ProductName -eq 'Test1.QA' } | Select -Expand ApplicationVersion
$UpdateVersion = $PropertyVersion.split(".")
$UpdateVersion[3] = 1+$UpdateVersion[3]
$newVersion = $UpdateVersion -join "."
$Test1QABuildVersion.Choose.when.PropertyGroup | ? { $_.ProductName -eq 'Test1.QA' } | %{$_.ApplicationVersion = $newVersion}
$TestQABuildVersion.Save($Test1QAMSBuildFile)
Below is code that will work on the example you have given. The main thing you need to keep in mind is that you are dealing with an xml object rather than a powershell object. Selecting the node to be updated requires using SelectSingleNode and specifying an x-path. Using the xml InnerText property allows you to get and set the value. The code below has been tested with the Test.csproj file you provided.
$Test1QAMSBuildFile = 'C:\Directory\Test.csproj'
[xml]$Test1QABuildVersion = Get-Content $Test1QAMSBuildFile
$node = $Test1QABuildVersion.SelectSingleNode("/Choose/When/PropertyGroup/ApplicationVersion[../ProductName = 'Test1.QA']")
$PropertyVersion= $node.InnerText
$UpdateVersion= $PropertyVersion.split(".")
$UpdateVersion[3] = (($UpdateVersion[3] -as [int]) + 1).ToString()
$newVersion = $UpdateVersion -join '.'
$node.InnerText = $newVersion
$Test1QABuildVersion.Save($Test1QAMSBuildFile)
In the case of a real csproj file you will also have to deal with namespaces since the Project element specifies a namespace. I've done bulk modifications to csproj files in the past and it involved quite a learning curve.

HP Warranty Lookup using PowerShell SOAP

Up to recently the web scraping of HP warranty information worked fine, however in the last couple of weeks they have changed the web page and it seems they are using POST rather than GET now on the new page, meaning I can't really just pass the information to the URL.
I did find some hope in a solution on this page:
http://ocdnix.wordpress.com/2013/03/14/hp-server-warranty-via-the-isee-api/
But I don't understand the example script as I have not worked with Python before.
I also found this web page that shows me a good example for Dell warranty, But HP don't have a WSDL that I could work with. (I would post the link but don't have enough rep)
Using these functions I can form the request:
http://www.iislogs.com/steveschofield/execute-a-soap-request-from-powershell
I think everything will work as expected but I am struggling to form the request to register the client, I keep getting 500 errors which either means their server is broken or my request is causing an internal error.
I am for the first time completely at a loss with this.
Anybody got this to work in PowerShell or having similar issues?
Updated 22-10-13
I now have the envelope, I managed to get the Python script to run but that failed because of my proxy, so extracted the generated XML which is what I wanted as I wasn't sure how it should be formed, this looks like:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:iseeReg="http://www.hp.com/isee/webservices/">
<SOAP-ENV:Body>
<iseeReg:RegisterClient2>
<iseeReg:request><isee:ISEE-Registration xmlns:isee="http://www.hp.com/schemas/isee/5.00/event" schemaVersion="5.00">
<RegistrationSource>
<HP_OOSIdentifiers>
<OSID>
<Section name="SYSTEM_IDENTIFIERS">
<Property name="TimestampGenerated" value="2013/10/22 09:40:35 GMT Standard Time"/>
</Section>
</OSID>
<CSID>
<Section name="SYSTEM_IDENTIFIERS">
<Property name="CollectorType" value="MC3"/>
<Property name="CollectorVersion" value="T05.80.1 build 1"/>
<Property name="AutoDetectedSystemSerialNumber" value="10"/>
<Property name="SystemModel" value="HP ProLiant"/>
<Property name="TimestampGenerated" value="2013/10/22 09:40:35 GMT Standard Time"/>
</Section>
</CSID>
</HP_OOSIdentifiers>
<PRS_Address>
<AddressType>0</AddressType>
<Address1/>
<Address2/>
<Address3/>
<Address4/>
<City/>
<Region/>
<PostalCode/>
<TimeZone/>
<Country/>
</PRS_Address>
</RegistrationSource>
<HP_ISEECustomer>
<Business/>
<Name/>
</HP_ISEECustomer>
<HP_ISEEPerson>
<CommunicationMode>255</CommunicationMode>
<ContactType/>
<FirstName/>
<LastName/>
<Salutation/>
<Title/>
<EmailAddress/>
<TelephoneNumber/>
<PreferredLanguage/>
<Availability/>
</HP_ISEEPerson>
</isee:ISEE-Registration></iseeReg:request>
</iseeReg:RegisterClient2>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
I then built a Powershell script that executes like this:
function Execute-SOAPRequest {
Param (
[Xml]$SOAPRequest,
[String]$URL,
[switch]$UseProxy
)
write-host "Sending SOAP Request To Server: $URL"
$soapWebRequest = [System.Net.WebRequest]::Create($URL)
$soapWebRequest.Headers.Add("SOAPAction",'"http://www.hp.com/isee/webservices/RegisterClient2"')
$soapWebRequest.ContentType = 'text/xml; charset=utf-8'
$soapWebRequest.Accept = "text/xml"
$soapWebRequest.Method = "POST"
$soapWebRequest.UserAgent = 'RemoteSupport/A.05.05 - gSOAP/2.7'
#$soapWebRequest.ServicePoint.Expect100Continue = $False
#$soapWebRequest.ServicePoint.MaxIdleTime = 2000
$soapWebRequest.ProtocolVersion = [system.net.httpversion]::version10
if($UseProxy){
$soapWebRequest.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials
}
write-host "Initiating Send."
$requestStream = $soapWebRequest.GetRequestStream()
$SOAPRequest.Save($requestStream)
$requestStream.Close()
write-host "Send Complete, Waiting For Response."
$resp = $soapWebRequest.GetResponse()
$responseStream = $resp.GetResponseStream()
$soapReader = [System.IO.StreamReader]($responseStream)
$ReturnXml = [Xml]$soapReader.ReadToEnd()
$responseStream.Close()
write-host "Response Received."
return $ReturnXml
}
$SOAPRequest = [Xml](Get-Content 'C:\Temp\SoapEnv.xml')
$URL = 'https://services.isee.hp.com/ClientRegistration/ClientRegistrationService.asmx'
Execute-SOAPRequest $SOAPRequest $URL -UseProxy
But now I am getting additional errors rather than the 500 I was getting so getting closer?? Error details are:
Exception calling "GetRequestStream" with "0" argument(s): "The server committed a protocol violation. Section=ResponseStatusLine"
At C:\Temp\HP Register Client.ps1:29 char:54
+ $requestStream = $soapWebRequest.GetRequestStream <<<< ()
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
try this. . works for me just fine: Note: Only the request tag needs to be escaped.
$SOAPRequest= [xml]#"
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:iseeReg="http://www.hp.com/isee/webservices/">
<SOAP-ENV:Body>
<iseeReg:RegisterClient2>
<iseeReg:request><isee:ISEE-Registration xmlns:isee="http://www.hp.com/schemas/isee/5.00/event" schemaVersion="5.00">
<RegistrationSource>
<HP_OOSIdentifiers>
<OSID>
<Section name="SYSTEM_IDENTIFIERS"&g`enter code here`t;
<Property name="TimestampGenerated" value="2013/12/06 14:04:24 EST"/>
</Section>
</OSID>
<CSID>
<Section name="SYSTEM_IDENTIFIERS">
<Property name="CollectorType" value="MC3"/>
<Property name="CollectorVersion" value="T05.80.1 build 1"/>
<Property name="AutoDetectedSystemSerialNumber" value="10"/>
<Property name="SystemModel" value="HP ProLiant"/>
<Property name="TimestampGenerated" value="2013/12/06 14:04:24 EST"/>
</Section>
</CSID>
</HP_OOSIdentifiers>
<PRS_Address>
<AddressType>0</AddressType>
<Address1/>
<Address2/>
<Address3/>
<Address4/>
<City/>
<Region/>
<PostalCode/>
<TimeZone/>
<Country/>
</PRS_Address>
</RegistrationSource>
<HP_ISEECustomer>
<Business/>
<Name/>
</HP_ISEECustomer>
<HP_ISEEPerson>
<CommunicationMode>255</CommunicationMode>
<ContactType/>
<FirstName/>
<LastName/>
<Salutation/>
<Title/>
<EmailAddress/>
<TelephoneNumber/>
<PreferredLanguage/>
<Availability/>
</HP_ISEEPerson>
</isee:ISEE-Registration></iseeReg:request>
</iseeReg:RegisterClient2>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
"#
You'll have to do the same thing for the warranty xml like so then just re-run the soap web request.
$hpgdid = $ReturnXml.envelope.body.RegisterClient2Response.RegisterClient2Result.Gdid
$hptoken = $ReturnXml.envelope.body.RegisterClient2Response.RegisterClient2Result.registrationtoken
$warrantyxml = [xml]#"
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:isee="http://www.hp.com/isee/webservices/">
<SOAP-ENV:Header>
<isee:IseeWebServicesHeader>
<isee:GDID>$hpgdid</isee:GDID>
<isee:registrationToken>$hptoken</isee:registrationToken>
<isee:OSID/>
<isee:CSID/>
</isee:IseeWebServicesHeader>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<isee:GetOOSEntitlementList2>
<isee:request>
<isee:ISEE-GetOOSEntitlementInfoRequest
xmlns:isee="http://www.hp.com/schemas/isee/5.00/entitlement"
schemaVersion="5.00">
<HP_ISEEEntitlementParameters>
<CountryCode>ES</CountryCode>
<SerialNumber>CZ10130050</SerialNumber>
<ProductNumber>519841-425</ProductNumber>
<EntitlementType></EntitlementType>
<EntitlementId></EntitlementId>
<ObligationId></ObligationId>
</HP_ISEEEntitlementParameters>
</isee:ISEE-GetOOSEntitlementInfoRequest>
</isee:request>
</isee:GetOOSEntitlementList2>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
"#
$xmlstring = [string]$ReturnXml.Envelope.Body.GetOOSEntitlementList2Response.GetOOSEntitlementList2Result.Response
$warranty_info = [xml]#"
$xmlstring
"#
$warranty_info."ISEE-GetOOSEntitlementInfoResponse"
I have built this into a PowerShell Module, I moved the SOAP Requests to separate XML files, and used CDATA to make them much more readable. It works pretty well for me. it can be found on GitHub:
https://github.com/dotps1/HPWarranty
Thanks for all of the info on this page, really helped!
You need to escape the XML being transferred like below. Also make sure that the TimestampGenerated is formatted properly as well.
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:iseeReg="http://www.hp.com/isee/webservices/">
<SOAP-ENV:Body>
<iseeReg:RegisterClient2>
<iseeReg:request><isee:ISEE-Registration xmlns:isee="http://www.hp.com/schemas/isee/5.00/event" schemaVersion="5.00">
<RegistrationSource>
<HP_OOSIdentifiers>
<OSID>
<Section name="SYSTEM_IDENTIFIERS">
<Property name="TimestampGenerated" value="2013/12/05 19:24:58 GMT"/>
</Section>
</OSID>
<CSID>
<Section name="SYSTEM_IDENTIFIERS">
<Property name="CollectorType" value="MC3"/>
<Property name="CollectorVersion" value="T05.80.1 build 1"/>
<Property name="AutoDetectedSystemSerialNumber" value="10"/>
<Property name="SystemModel" value="HP ProLiant"/>
<Property name="TimestampGenerated" value="2013/12/05 19:24:58 GMT"/>
</Section>
</CSID>
</HP_OOSIdentifiers>
<PRS_Address>
<AddressType>0</AddressType>
<Address1/>
<Address2/>
<Address3/>
<Address4/>
<City/>
<Region/>
<PostalCode/>
<TimeZone/>
<Country/>
</PRS_Address>
</RegistrationSource>
<HP_ISEECustomer>
<Business/>
<Name/>
</HP_ISEECustomer>
<HP_ISEEPerson>
<CommunicationMode>255</CommunicationMode>
<ContactType/>
<FirstName/>
<LastName/>
<Salutation/>
<Title/>
<EmailAddress/>
<TelephoneNumber/>
<PreferredLanguage/>
<Availability/>
</HP_ISEEPerson>
</isee:ISEE-Registration></iseeReg:request>
</iseeReg:RegisterClient2>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Another option instead of escaping the XML yourself would be to place it within a CDATA so that it isn't parsed: http://www.w3schools.com/xml/xml_cdata.asp
Combining all the information I found all over the web, I've created the following function that does it all based on the Serial Number. Special thanks to dotps1 for his hard work.
For HP:
Function Get-HPAssetInformationHC {
[CmdletBinding()]
Param (
[Parameter(Mandatory,ValueFromPipeline)]
[String]$SerialNumber
)
Begin {
Function Invoke-HPIncSOAPRequest {
Param (
[Parameter(Mandatory)]
[Xml]$SOAPRequest,
[String]$Url = 'https://api-uns-sgw.external.hp.com/gw/hpit/egit/obligation.sa/1.1'
)
$soapWebRequest = [System.Net.WebRequest]::Create($URL)
$soapWebRequest.Headers.Add('X-HP-SBS-ApplicationId','hpi-obligation-hpsa')
$soapWebRequest.Headers.Add('X-HP-SBS-ApplicationKey','ft2VGa2hx9j$')
$soapWebRequest.ContentType = 'text/xml; charset=utf-8'
$soapWebRequest.Accept = 'text/xml'
$soapWebRequest.Method = 'POST'
try {
$SOAPRequest.Save(($requestStream = $soapWebRequest.GetRequestStream()))
$requestStream.Close()
$responseStream = ($soapWebRequest.GetResponse()).GetResponseStream()
[XML]([System.IO.StreamReader]($responseStream)).ReadToEnd()
$responseStream.Close()
}
catch {
throw $_
}
}
}
Process {
foreach ($S in $SerialNumber) {
$request = #"
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:int="http://interfaces.obligation.sbs.it.hp.com/">
<soapenv:Header />
<soapenv:Body>
<int:retrieveServiceObligationResponsesByServiceObligationRequests>
<context>
<appContextName>HPSF</appContextName>
<userLocale>en-US</userLocale>
</context>
<obligationRequests>
<lnkServiceObligationDepthFilter>
<includeProductObjectOfServiceInstance>true</includeProductObjectOfServiceInstance>
<includeServiceObligation>true</includeServiceObligation>
<includeServiceObligationHeaderOffer>true</includeServiceObligationHeaderOffer>
<includeServiceObligationMessage>true</includeServiceObligationMessage>
<maxNumberOfProductObjectOfServiceInstance>100</maxNumberOfProductObjectOfServiceInstance>
</lnkServiceObligationDepthFilter>
<lnkServiceObligationEnrichment>
<iso2CountryCode>US</iso2CountryCode>
</lnkServiceObligationEnrichment>
<lnkServiceObligationProductObjectOfServiceIdentifier>
<hpSerialNumber>$S</hpSerialNumber>
</lnkServiceObligationProductObjectOfServiceIdentifier>
</obligationRequests>
</int:retrieveServiceObligationResponsesByServiceObligationRequests>
</soapenv:Body>
</soapenv:Envelope>
"#
Try {
[XML]$entitlement = Invoke-HPIncSoapRequest -SOAPRequest $request -ErrorAction Stop
}
Catch {
$P = $_
$Global:Error.RemoveAt(0)
throw "Failed to invoke SOAP request: $P"
}
Try {
if ($entitlement) {
$HPAsset = $entitlement.Envelope.Body.retrieveServiceObligationResponsesByServiceObligationRequestsResponse.return
[PSCustomObject][Ordered]#{
SerialNumber = $S
ProductNumber = $HPAsset.lnkProductObjectOfServiceInstance.ProductNumber
SalesOrderNumber = $HPAsset.lnkServiceObligations.salesOrderNumber | where {$_}
ProductDescription = $HPAsset.lnkProductObjectOfServiceInstance.productDescription
ProductLineDescription = $HPAsset.lnkProductObjectOfServiceInstance.productLineDescription
ActiveEntitlement = $HPAsset.lnkServiceObligations.serviceObligationActiveIndicator
OfferDescription = $HPAsset.lnkServiceObligationHeaderOffer | where serviceQuantity -GE 1 | Select-Object -ExpandProperty offerDescription
StartDate = $HPAsset.lnkServiceObligations.serviceObligationStartDate | ForEach-Object {[DateTime]$_}
EndDate = $HPAsset.lnkServiceObligations.serviceObligationEndDate | ForEach-Object {[DateTime]$_}
}
Write-Verbose "HP asset '$($HPAsset.lnkProductObjectOfServiceInstance.productDescription)' with serial number '$S'"
}
else {
Write-Warning "No HP asset information found for serial number '$S'"
continue
}
}
Catch {
$P = $_
$Global:Error.RemoveAt(0)
throw "Failed to invoke SOAP request: $P"
}
}
}
}
For Dell:
Function Get-DellAssetInformationHC {
[CmdletBinding()]
Param(
[Parameter(Mandatory, ValueFromPipeline)]
[String[]]$SerialNumber
)
Begin {
# Possible API keys
# 1adecee8a60444738f280aad1cd87d0e
# d676cf6e1e0ceb8fd14e8cb69acd812d
# 1adecee8a60444738f280aad1cd87d0e
# 849e027f476027a394edd656eaef4842
$APIKey = '849e027f476027a394edd656eaef4842'
}
Process {
foreach ($S in $SerialNumber) {
Try {
$DellURL = "https://api.dell.com/support/v2/assetinfo/warranty/tags.xml?svctags=$S&apikey=$APIKey"
$XML = New-Object System.Xml.XmlDocument
$XML.Load($DellURL)
$DellAsset = $XML.GetAssetWarrantyResponse.GetAssetWarrantyResult.Response.DellAsset
if ($DellAsset) {
[PSCustomObject][Ordered]#{
SerialNumber = $S
CustomerNumber = $DellAsset.CustomerNumber
OrderNumber = $DellAsset.OrderNumber
MachineDescription = $DellAsset.MachineDescription
ShipDate = $DellAsset.ShipDate
ServiceLevelDescription = $DellAsset.Warranties.Warranty.ServiceLevelDescription
StartDate = $DellAsset.Warranties.Warranty.StartDate | ForEach-Object {[DateTime]$_}
EndDate = $DellAsset.Warranties.Warranty.EndDate | ForEach-Object {[DateTime]$_}
}
Write-Verbose "Dell asset '$($DellAsset.MachineDescription)' with serial number '$S'"
}
else {
Write-Warning "No Dell asset information found for serial number '$S'"
}
}
Catch {
$P = $_
$Global:Error.RemoveAt(0)
throw "Failed retrieving Dell asset information for serial number '$S': $P"
}
}
}
}
Any reason why we cannot just do a http POST against the publicly available URL: http://h20564.www2.hpe.com/hpsc/wc/public/find
We can do an http POST with curl like this (put this in a script, for example):
/usr/bin/curl 'http://h20564.www2.hpe.com/hpsc/wc/public/find' \
--compressed \
-H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8' \
-H 'Accept-Encoding: gzip, deflate' \
-H 'Accept-Language: en-US,en;q=0.5' \
-H 'Connection: keep-alive' \
-H 'Host: h20564.www2.hpe.com' \
-H 'Referer: (missing https: here) h20564.www2.hpe.com/hpsc/wc/public/home' \
-H 'Upgrade-Insecure-Requests: 1' \
-H 'User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:49.0) Gecko/20100101 Firefox/49.0' \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data-binary '#/tmp/data' | grep hpui-standard-table
The only extra thing it needs the -H 'Cookie: ' header. I can copy the same cookie from a web lookup, but I am not sure how long that can be used.
The data file is in /tmp/data, formatted like this:
rows[0].item.countryCode=US rows[0].item.serialNumber=XXXXXXXXX
rows[1].item.countryCode=US rows[1].item.serialNumber=YYYYYYYYY
rows[2].item.countryCode=US rows[2].item.serialNumber=
rows[3].item.countryCode=US rows[3].item.serialNumber=
rows[4].item.countryCode=US rows[4].item.serialNumber=
rows[5].item.countryCode=US rows[5].item.serialNumber=
rows[6].item.countryCode=US rows[6].item.serialNumber=
rows[7].item.countryCode=US rows[7].item.serialNumber=
rows[8].item.countryCode=US rows[8].item.serialNumber=
rows[9].item.countryCode=US rows[9].item.serialNumber=
submitButton=Submit
Now HP has developed api for getting machines product warranty. It is in testing phase however we can try it. Hope it will be moved to production As Soon As Possible. You have to go through the document here and fill the details they required. You will have your own api key to work with.
https://developers.hp.com/css-enroll
Thanks,
Prabha.

How to use InsertAfter with PowerShell

I have some xml files where I want to insert the contents of one xml file into another. I thought I'd use LastChild and the InsertAfter method to accomplish this. So far it's not working for me.
Here is the parent.xml file:
<manifest>
<manifestExecution>
<assetDetail>
<fileAsset fileAssetGuid="parentguid1">
<parentfile1 />
</fileAsset>
<fileAsset fileAssetGuid="parentguid2">
<parentfile2 />
</fileAsset>
</assetDetail>
</manifestExecution>
</manifest>
And here is the child.xml file:
<manifest>
<manifestExecution>
<assetDetail>
<fileAsset fileAssetGuid="childguid1">
<childfile1 />
</fileAsset>
</assetDetail>
</manifestExecution>
</manifest>
What I want to do is select the fileAsset node(s) from child.xml and insert into parent.xml after the last fileAsset node in parent.xml.
Here is my test code:
$parent = [xml] (Get-Content d:\temp\parent.xml)
$parentnode = $parent.manifest.manifestExecution.assetDetail
$child = [xml] (Get-Content d:\temp\child.xml)
$childnode = $child.manifest.manifestExecution.assetDetail.InnerXml
$parentnode.InsertAfter($childnode, $parentnode.LastChild)
Here is the error msg I'm getting:
Cannot convert argument "0", with value: "<fileAsset fileAssetGuid="childguid1"> <childfile1 /></fileAsset>", for "InsertAfter" to type "System.Xml.XmlNode": "Cannot conver
t the "<fileAsset fileAssetGuid="childguid1"><childfile1 /></fileAsset>" value of type "System.String" to type "System.Xml.XmlNode"."
At line:5 char:24
+ $parentnode.InsertAfter <<<< ($childnode, $parentnode.LastChild)
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument
What am I doing wrong?
You need to iterate through $childnode's children, remove them from their parent, and import them into the new document context ($child and $parent are different XmlDocument instances) before appending to $parentnode.
This will append all fileAsset nodes from $childnode into $parentnode.
$parent = [xml](get-content d:\temp\parent.xml)
$parentnode = $parent.manifest.manifestexecution.assetdetail
$child = [xml](get-content d:\temp\child.xml)
$childnode = $child.manifest.manifestexecution.assetdetail
while ($childnode.haschildnodes) {
$cn = $childnode.firstchild
$cn = $childnode.removechild($cn)
$cn = $parentnode.ownerdocument.importnode($cn, $true)
$parentnode.appendchild($cn)
}
Fortunately, most of these methods return the same XmlNode or a new version of it, so the body of the while loop could chained together like this:
$parentnode.appendchild( $parentnode.ownerdocument.importnode( $childnode.removechild( $childnode.firstchild ), $true ))
InsertAfter(newChild,referenceChild) could also work, but would be done a little differently since it also needs a reference to the the node that it will be inserted after.
your first problem is that you're not getting an XML element, but a string. You need to get an XML node from your XML document, but the shorthand method you're using is guessing you want a string. Usually you can force it by explicitly casting it over to [System.Xml.XmlElement], but that doesn't always work. You can reliably get an element using "SelectSingleNode".
You've not hit your second problem yet, but it's just around the corner. Once you've got XML, it still won't work because it's from a different XML document, so you need to "Import" the node. You'll want to tweak this to get the XML to align the way you envision, but the code works.
$parentString = #"
<manifest>
<manifestExecution>
<assetDetail>
<fileAsset fileAssetGuid="parentguid1">
<parentfile1 />
</fileAsset>
<fileAsset fileAssetGuid="parentguid2">
<parentfile2 />
</fileAsset>
</assetDetail>
</manifestExecution>
</manifest>
"#
$childString = #"
<manifest>
<manifestExecution>
<assetDetail>
<fileAsset fileAssetGuid="childguid1">
<childfile1 />
</fileAsset>
</assetDetail>
</manifestExecution>
</manifest>
"#
$parent = [xml] ($parentString)
$parentnode = $parent.manifest.manifestExecution.assetDetail
$child = [xml] ($childString)
$xpath = '/manifest/manifestExecution/assetDetail'
$childnode = $child.SelectSingleNode($xpath)
Write-Host("So the child is $($childnode.OuterXML)")
$importedNode = $parent.ImportNode($childNode,$true)
Write-Host("And after importing: $($importedNode.OuterXML)")
$parentnode.InsertAfter($importednode, $parentnode.LastChild)
Write-Host("To finally yield: $($parent.OuterXML)")
Also, you may find you can use something like your original code if you cast it to XmlElement properly.
$childnode = [System.Xml.XmlElement]$child.manifest.manifestExecution.assetDetail.InnerXml