{"id":3286,"date":"2013-07-03T00:01:00","date_gmt":"2013-07-03T00:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2013\/07\/03\/using-the-live-rest-api-with-powershell\/"},"modified":"2013-07-03T00:01:00","modified_gmt":"2013-07-03T00:01:00","slug":"using-the-live-rest-api-with-powershell","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/using-the-live-rest-api-with-powershell\/","title":{"rendered":"Using the Live REST API with PowerShell"},"content":{"rendered":"<p><strong style=\"font-size: 12px\">Summary<\/strong><span style=\"font-size: 12px\">: Microsoft PFE, Chris Wu talks about using the Live REST API with Windows PowerShell.<\/span><\/p>\n<p>Microsoft Scripting Guy, Ed Wilson, is here. Once again we have Chris Wu with us. For previous posts from Chris, see the <a href=\"http:\/\/blogs.technet.com\/b\/heyscriptingguy\/archive\/tags\/chris+wu\/\" target=\"_blank\">Hey, Scripting Guy! Blog<\/a>. Take it away Chris&hellip;<\/p>\n<p>In this post, we will show off some miscellaneous tasks that are enabled by the Live REST API. Again, the following code snippets assume that a valid <strong>$AccessToken<\/strong> with appropriate scope has been returned. For information about how to create a valid access token, read my post, <a href=\"http:\/\/blogs.technet.com\/b\/heyscriptingguy\/archive\/2013\/07\/01\/use-powershell-3-0-to-get-more-out-of-windows-live.aspx\" target=\"_blank\">Use PowerShell 3.0 to Get More Out of Windows Live<\/a>.<\/p>\n<p>In this post, I&rsquo;ll discuss how to:<\/p>\n<ul>\n<li><span style=\"font-size: 12px\">Enumerate and search for contacts<\/span><\/li>\n<li><span style=\"font-size: 12px\">Interact with calendars and calendar events<\/span><\/li>\n<li><span style=\"font-size: 12px\">Create a new contact<\/span><\/li>\n<\/ul>\n<h2>Enumerate and search for contacts<\/h2>\n<p style=\"padding-left: 30px\"><strong>Note<\/strong>&nbsp;&nbsp;&nbsp;This task requires the <strong>wl.basic<\/strong> scope.<\/p>\n<p>To enumerate contacts of currently signed-in user, send a request to <strong>me\/contacts<\/strong>:<\/p>\n<p style=\"padding-left: 30px\">$ApiUri = &#8220;https:\/\/apis.live.net\/v5.0&#8221;<\/p>\n<p style=\"padding-left: 30px\">Invoke-RestMethod -Uri &#8220;$ApiUri\/me\/contacts?access_token=$AccessToken&#8221;<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/0535.hsg-7-3-13-1.png\"><img decoding=\"async\" title=\"Image of command output\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/0535.hsg-7-3-13-1.png\" alt=\"Image of command output\" \/><\/a><\/p>\n<p>Note that the listed contact objects have a property called <strong>email_hashes<\/strong>, which is an array that contains a hash for each email address that user possesses. The purpose of using this hash is apparently to protect confidential information from being transmitted in clear text.<\/p>\n<p>Searching for a contact by first and last name can be easily done with our old friend <strong>Where-Object<\/strong>:<\/p>\n<p style=\"padding-left: 30px\">(Invoke-RestMethod -Uri &#8220;$ApiUri\/me\/contacts?access_token=$AccessToken&#8221;).data | Where-Object { $_.first_name -eq &#8216;Chris&#8217; -and $_.last_name -eq &#8216;Wu&#8217; }<\/p>\n<p>If you are running Windows PowerShell&nbsp;3.0, the following new syntax will come in handy:<\/p>\n<p style=\"padding-left: 30px\">(Invoke-RestMethod -Uri &#8220;$ApiUri\/me\/contacts?access_token=$AccessToken&#8221;).data | ? name -like &#8216;Chris Wu&#8217;<\/p>\n<p>To search for a contact by email address, however, involves a little more work. We need the hash, which technically is a SHA256 hash of UTF8 encoding of the email address concatenated with the script&rsquo;s client ID. So here is the script:<\/p>\n<p style=\"padding-left: 30px\">$Email = &#8220;chris@contoso.com&#8221;.Trim()<\/p>\n<p style=\"padding-left: 30px\">$hash = -join ((new-object System.Security.Cryptography.SHA256CryptoServiceProvider).ComputeHash( `<\/p>\n<p style=\"padding-left: 30px\">&nbsp; (new-object System.Text.UTF8Encoding).GetBytes(&#8220;$Email$ClientID&#8221;.ToLower())) | `<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; %{ $_.ToString(&#8220;x2&#8221;) })<\/p>\n<p style=\"padding-left: 30px\">(Invoke-RestMethod -Uri &#8220;$ApiUri\/me\/contacts?access_token=$AccessToken&#8221;).data | ? email_hashes -Contains $hash<\/p>\n<p>The <strong>user_id<\/strong> property of the object (if present) in the previous examples identifies the Microsoft account for that contact. An application can request the corresponding user object to retrieve more details. However, sensitive information such as birthday, work profile, email addresses, postal address, and phone numbers are granularly controlled through additional scopes: <strong>wl.birthday<\/strong>, <strong>wl.work_profile<\/strong>, <strong>wl.emails<\/strong>, <strong>wl.postal_addresses<\/strong>, <strong>wl.phone_numbers<\/strong>.<\/p>\n<p>This model works great for commercial applications to gather user information per a user&rsquo;s consent. But for a Windows PowerShell script that&rsquo;s not used by a large user base (usually run by a single user like me), this means difficulty in getting those additional fields.<\/p>\n<p>Anyway, the following snippet returns the user object of a contact with a valid user ID:<\/p>\n<p style=\"padding-left: 30px\">$UserID = ((Invoke-RestMethod -Uri &#8220;$ApiUri\/me\/contacts?access_token=$AccessToken&#8221;).data | ? name -like &#8216;Chris Wu&#8217;).user_id<\/p>\n<p style=\"padding-left: 30px\">Invoke-RestMethod -Uri &#8220;$ApiUri\/$UserID`?access_token=$AccessToken&#8221;<\/p>\n<h2>Create a new contact<\/h2>\n<p style=\"padding-left: 30px\"><strong>Note<\/strong>&nbsp;&nbsp;&nbsp;This task requires the <strong>wl.calendars<\/strong> scope.<\/p>\n<p>A <strong>Post<\/strong> request like this will create a new contact:<\/p>\n<p style=\"padding-left: 30px\">$contact = @{<\/p>\n<p style=\"padding-left: 30px\">&nbsp; first_name=&#8221;Jack&#8221;;<\/p>\n<p style=\"padding-left: 30px\">&nbsp; last_name=&#8221;Smith&#8221;;<\/p>\n<p style=\"padding-left: 30px\">&nbsp; emails=@{preferred=&#8221;jsmith@contoso.com&#8221;;business=&#8221;Jack.Smith@contoso.com&#8221;}<\/p>\n<p style=\"padding-left: 30px\">} | ConvertTo-Json<\/p>\n<p style=\"padding-left: 30px\">Invoke-RestMethod -Uri &#8220;$ApiUri\/me\/contacts?access_token=$AccessToken&#8221; -Method Post -ContentType &#8220;application\/json&#8221; -Body $contact<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/8686.hsg-7-3-13-2.png\"><img decoding=\"async\" title=\"Image of command output\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/8686.hsg-7-3-13-2.png\" alt=\"Image of command output\" \/><\/a><\/p>\n<p>In this example, we piped a hash table to the <strong>ConvertTo-Json<\/strong> cmdlet to get the JSON representation, which can be passed as the body of the <strong>Post<\/strong> request.<\/p>\n<h2>Interact with calendars and calendar events<\/h2>\n<p style=\"padding-left: 30px\"><strong>Note<\/strong>&nbsp;&nbsp;This task requires the <strong>wl.contacts_create<\/strong> scope.<\/p>\n<p>Interacting with calendars by using the <strong>Rest<\/strong> method is pretty straightforward. Most tasks can easily be accomplished through the Windows PowerShell <strong>Invoke-RestMethod<\/strong> cmdlet. The tasks are also well documented at <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/live\/hh826523.aspx#cal_rest\" target=\"_blank\">Interacting with calendars (Live Connect API)<\/a>.<\/p>\n<p>Let&rsquo;s say that I have added Canadian public holidays to my calendar by following these instructions: <a href=\"http:\/\/windows.microsoft.com\/en-us\/windows\/outlook\/calendar-holiday-other?woldogcb=0\">Add holiday or lunar calendars to Outlook.com<\/a>. The following snippet will enumerate all the calendars I have in my account:<\/p>\n<p style=\"padding-left: 30px\">(Invoke-RestMethod -Uri &#8220;$ApiUri\/me\/calendars?access_token=$AccessToken&#8221;).data<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/2664.hsg-7-3-13-3.png\"><img decoding=\"async\" title=\"Image of command output\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/2664.hsg-7-3-13-3.png\" alt=\"Image of command output\" \/><\/a><\/p>\n<p>To unsubscribe to the Canadian holiday calendar, I simply send a <strong>Delete<\/strong> request:<\/p>\n<p style=\"padding-left: 30px\">$CalendarID = ((Invoke-RestMethod -Uri &#8220;$ApiUri\/me\/calendars?access_token=$AccessToken&#8221;).data | ? {$_.name -eq &#8220;Canada Holidays&#8221;}).id<\/p>\n<p style=\"padding-left: 30px\">Invoke-RestMethod -Uri &#8220;$ApiUri\/$CalendarID`?access_token=$AccessToken&#8221; -Method Delete<\/p>\n<p>Similarly, sending a request to <strong>me\/events<\/strong> will return a list of calendar events (seemingly for the next 30 days):<\/p>\n<p style=\"padding-left: 30px\">Invoke-RestMethod -Uri &#8220;$ApiUri\/me\/events?access_token=$AccessToken&#8221;<\/p>\n<p>Unfortunately, even though the documentation states that the REST API supports subscribing to and creating calendars, I can&rsquo;t seem to make it work. (Yes, I double checked that the required scopes are enabled.) If any reader finds a solution and comments to this post, it will be very much appreciated.<\/p>\n<p>After playing with the Live SDK, I personally find the Live REST API strong in supporting SkyDrive, but lacking in other areas. Understandably, this is probably due to the transition from Hotmail to Outlook.com, and Live Messenger to Skype. Hopefully after all the transitions are complete, Microsoft will release a new version of Live SDK to fill the gaps.<\/p>\n<p>One last piece of information before I conclude this series of blog posts: All applications that use Windows Live services and have requested user permissions are listed on the <a href=\"https:\/\/account.live.com\/consent\/Manage\">User&rsquo;s Apps and Services setting page<\/a>. As a user, it may be a good idea to regularly visit this page to revoke access or remove obsolete applications.<\/p>\n<p>~Chris<\/p>\n<p>That&rsquo;s it this week for Chris Wu. Thanks again, Chris, for sharing your time and knowledge.<\/p>\n<p>I invite you to follow me on <a href=\"http:\/\/bit.ly\/scriptingguystwitter\" target=\"_blank\">Twitter<\/a> and <a href=\"http:\/\/bit.ly\/scriptingguysfacebook\" target=\"_blank\">Facebook<\/a>. If you have any questions, send email to me at <a href=\"mailto:scripter@microsoft.com\" target=\"_blank\">scripter@microsoft.com<\/a>, or post your questions on the <a href=\"http:\/\/bit.ly\/scriptingforum\" target=\"_blank\">Official Scripting Guys Forum<\/a>. See you tomorrow. Until then, peace.<\/p>\n<p><strong>Ed Wilson, Microsoft Scripting Guy<span style=\"font-size: 12px\">&nbsp;<\/span><\/strong><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Summary: Microsoft PFE, Chris Wu talks about using the Live REST API with Windows PowerShell. Microsoft Scripting Guy, Ed Wilson, is here. Once again we have Chris Wu with us. For previous posts from Chris, see the Hey, Scripting Guy! Blog. Take it away Chris&hellip; In this post, we will show off some miscellaneous tasks [&hellip;]<\/p>\n","protected":false},"author":596,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[302,56,434,3,167,45],"class_list":["post-3286","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-chris-wu","tag-guest-blogger","tag-invoke-restmethod","tag-scripting-guy","tag-using-the-internet","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>Summary: Microsoft PFE, Chris Wu talks about using the Live REST API with Windows PowerShell. Microsoft Scripting Guy, Ed Wilson, is here. Once again we have Chris Wu with us. For previous posts from Chris, see the Hey, Scripting Guy! Blog. Take it away Chris&hellip; In this post, we will show off some miscellaneous tasks [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/3286","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/596"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=3286"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/3286\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=3286"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=3286"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=3286"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}