• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 3247
  • Last Modified:

New-WebServiceProxy passing sessionId to SOAP header

Ok, I'm dieing here.  Somebody help me out please.  Here's what I have going on:

I am trying to design a Powershell script that will connect to salesforce and retrieve information.  The script I have so far will allow me to connect to the salesforce API and login, and it returns a sessionId in "$sf.loginResponse.SessionId".  I want to take this session ID and insert it into the session header so that I can run API calls.  Here is what I have so far:

$URI = "[insert-full-path-to-file]\salesforce-api-partner.wsdl"
$username = "michael1@desktopninjas.com"
$password = "testtest171XKd4g57k4KFgXHk7QbK8Kc7"

$sf = New-WebServiceProxy -Uri $URI -Namespace sf -UseDefaultCredential
$sf
$LoginResponse = $sf.login($username, $password)
$LoginResponse
$newSession = $LoginResponse.sessionId
$newSession
$newURL = $LoginResponse.serverUrl
$sf.Url = $newURL
$sf.Url
$sf.SessionHeaderValue.sessionId = $newSession
$soapQuery = $sf.query("SELECT Name FROM Lead")
$sf.logout()

Open in new window


Yes, I know there a password in there.  This is just a developer account.  There's no sensitive info in it and I'll change it once we fix this.  

This script gives me the following errors in Powershell ISE 3.0:

The property 'sessionId' cannot be found on this object. Verify that the property exists and can be set.
At C:\Users\mlucas\Dropbox\Desktop Ninjas\Clients\CCC\powershell-dev\0.1\soap-request2.ps1:20 char:1
+ $sf.SessionHeaderValue.sessionId = $newSession
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : PropertyNotFound
 
Exception calling "query" with "1" argument(s): "INVALID_SESSION_ID: Invalid Session ID found in SessionHeader: Illegal Session"
At C:\Users\mlucas\Dropbox\Desktop Ninjas\Clients\CCC\powershell-dev\0.1\soap-request2.ps1:21 char:1
+ $soapQuery = $sf.query("SELECT Name FROM Lead")
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : SoapException
 
Exception calling "logout" with "0" argument(s): "INVALID_SESSION_ID: Invalid Session ID found in SessionHeader: Illegal Session"
At C:\Users\mlucas\Dropbox\Desktop Ninjas\Clients\CCC\powershell-dev\0.1\soap-request2.ps1:22 char:1
+ $sf.logout()
+ ~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : SoapException

Open in new window


I've tried to add-member but I'll not very good at it and I can't figure it out.  If anyone can help me with this step I will reward generously.  I've attached the script and WSDL file (in text format) for your review.
salesforce-api-partner.wsdl.txt
soap-request2.ps1.txt
0
orther
Asked:
orther
  • 2
1 Solution
 
ortherAuthor Commented:
It seems like using the defined namespace "#sf.Url" or #loginResponse.sessionId" I am able to add them to variables and process them, but anything to do with the header doesn't stick.  If you look in the SOAP envelope for query(), you'll see that the envelope is not expecting the sessionId in the body, but in the header.  There's something I'm missing here.

This envelope actually works from SOAP-UI to pull data:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:partner.soap.sforce.com">
   <soapenv:Header>
      <urn:SessionHeader>
         <urn:sessionId>00Di0000000iRH2!AQoAQL2N1aUx8D8j3ViQ.7lV0qcxIAZmsG3SEy9wfIz9saCKw4DXWZIeD5Yl8V52_2.7cBNMyw6bvlycbB4r0VxIZ5VVfT9H</urn:sessionId>
      </urn:SessionHeader>
   </soapenv:Header>
   <soapenv:Body>
      <urn:query>
         <urn:queryString>SELECT Email FROM Lead WHERE Name = 'Michael Lucas'</urn:queryString>
      </urn:query>
   </soapenv:Body>
</soapenv:Envelope>

Open in new window


Comes back as this:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns="urn:partner.soap.sforce.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:sf="urn:sobject.partner.soap.sforce.com">
   <soapenv:Header>
      <LimitInfoHeader>
         <limitInfo>
            <current>789</current>
            <limit>5000</limit>
            <type>API REQUESTS</type>
         </limitInfo>
      </LimitInfoHeader>
   </soapenv:Header>
   <soapenv:Body>
      <queryResponse>
         <result xsi:type="QueryResult">
            <done>true</done>
            <queryLocator xsi:nil="true"/>
            <records xsi:type="sf:sObject">
               <sf:type>Lead</sf:type>
               <sf:Id xsi:nil="true"/>
               <sf:Email>michael@desktopninjas.com</sf:Email>
            </records>
            <size>1</size>
         </result>
      </queryResponse>
   </soapenv:Body>
</soapenv:Envelope>

Open in new window

0
 
ortherAuthor Commented:
OK, great bunch of help you guys are.  ;-)  Just kidding.  Here's what I came up with:

Instead of trying to add the sessionID into the object pipeline for New-WebServiceProxy, I decided to go a different route and use Invoke-WebRequest to send pre-built SOAP envelopes stored in here-strings.  The full code is below.  For those of you who are trying to connect powershell to Salesforce, this is the best way, trust me.  Powershell handles XML like a champ!  Just pipes the XML response right into an Object collection and you can start working with it.

# Set some variables (need to pipe these in from config.xml later in development)
$URI = "C:\Users\mlucas\Dropbox\Desktop Ninjas\Clients\CCC\powershell-dev\0.1\salesforce-api-partner.wsdl"
$username = "[omitted]"
$password = "[omitted]

# New-WebServiceProxy to call login() through salesforce API
write-progress -activity "Connecting to SalesForce API" -status "10% Complete:" -percentcomplete 10;
$service = New-WebServiceProxy -Uri $URI -Namespace service -UseDefaultCredential

write-progress -activity "Pulling Variables" -status "25% Complete:" -percentcomplete 25;
# grab LoginResponse and pull sessionId and serverUrl for the next calls
$LoginResponse = $service.login($username, $password)
$sessionID = $LoginResponse.sessionId
$newURL = $LoginResponse.serverUrl

write-progress -activity "Building Functions" -status "50% Complete:" -percentcomplete 50;
# build function to call query() in salesforce API
function Call-SFQuery([string]$sessionID, [string]$query1, [string]$newURL)
{
$queryBody = [xml] @"
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:partner.soap.sforce.com">
   <soapenv:Header>
      <urn:SessionHeader>
         <urn:sessionId>$sessionID</urn:sessionId>
      </urn:SessionHeader>
   </soapenv:Header>
   <soapenv:Body>
      <urn:query>
         <urn:queryString>$query1</urn:queryString>
      </urn:query>
   </soapenv:Body>
</soapenv:Envelope>
"@

Invoke-WebRequest $newURL -Method Post -Headers @{SOAPAction=$newURL} -ContentType "text/xml" -Body $queryBody
}

# build function to call logout() in salesforce API
function Call-SFLogout([string]$sessionID)
{
$queryBody = [xml] @"
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:partner.soap.sforce.com">
   <soapenv:Header>
      <urn:SessionHeader>
         <urn:sessionId>$sessionID</urn:sessionId>
      </urn:SessionHeader>
   </soapenv:Header>
   <soapenv:Body>
      <urn:logout/>
   </soapenv:Body>
</soapenv:Envelope>
"@

Invoke-WebRequest $newURL -Method Post -Headers @{SOAPAction=$newURL} -ContentType "text/xml" -Body $queryBody
}

# Set query and pipe to XML enabled variable so it sets it up in object collection
write-progress -activity "Executing Query" -status "80% Complete:" -percentcomplete 80;
$query1 = "SELECT Name, Email From Lead"
[xml]$response = Call-SFQuery $sessionID $query1 $newURL

# set some variable from 
$records = $response.Envelope.Body.queryResponse.result.records
$names = $response.Envelope.Body.queryResponse.result.records.name
$emails = $response.Envelope.Body.queryResponse.result.records.email

# call logout (optional at this point)
write-progress -activity "Logging Out" -status "100% Complete:" -percentcomplete 100;
$logoutReturn = Call-SFLogout $sessionID

# one way to work with the data
$names | Format-Table -Property name,email

# for each loop using object collections as data.
$records | ForEach-Object {
$_.name
$_.email
}

Open in new window

0

Featured Post

Who's Defending Your Organization from Threats?

Protecting against advanced threats requires an IT dream team – a well-oiled machine of people and solutions working together to defend your organization. Download our resource kit today to learn more about the tools you need to build you IT Dream Team!

  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now