Solved

New-WebServiceProxy passing sessionId to SOAP header

Posted on 2013-12-05
2
2,488 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
Comment Utility
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
Comment Utility
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

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Our Group Policy work started with Small Business Server in 2000. Microsoft gave us an excellent OU and GPO model in subsequent SBS editions that utilized WMI filters, OU linking, and VBS scripts. These are some of experiences plus our spending a lo…
International Data Corporation (IDC) prognosticates that before the current the year gets over disbursing on IT framework products to be sent in cloud environs will be $37.1B.
This video teaches viewers how to create their own website using cPanel and Wordpress. Tutorial walks users through how to set up their own domain name from tools like Domain Registrar, Hosting Account, and Wordpress. More specifically, the order in…
Learn how to set-up PayPal payment integration in your Wufoo form. Allow your users to remit payment through PayPal upon completion of your online form. This is helpful for collecting membership payments, customer payments, donations, and more.

771 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

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now