Solved

New-WebServiceProxy passing sessionId to SOAP header

Posted on 2013-12-05
2
2,715 Views
Last Modified: 2016-02-26
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
Comment
Question by:orther
  • 2
2 Comments
 

Author Comment

by:orther
ID: 39699422
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
 

Accepted Solution

by:
orther earned 0 total points
ID: 39703965
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

Salesforce Made Easy to Use

On-screen guidance at the moment of need enables you & your employees to focus on the core, you can now boost your adoption rates swiftly and simply with one easy tool.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Video and audio capture on Windows 7 3 101
Video on my site 4 74
Migrate Application To New Mac 5 58
Forms that calculate points for wordpress 10 52
Email signature management is something that is often overlooked in many organizations or is simply not implemented effectively. Let's take a look at what methods are available for managing this important piece of corporate branding.
You may have a outside contractor who comes in once a week or seasonal to do some work in your office but you only want to give him access to the programs and files he needs and keep privet all other documents and programs, can you do this on a loca…
This video teaches users how to migrate an existing Wordpress website to a new domain.
Use Wufoo, an online form creation tool, to make powerful forms. Learn how to choose which pages of your form are visible to your users based on their inputs. The page rules feature provides you with an opportunity to create if:then statements for y…

830 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question