{"id":944,"date":"2015-07-21T08:44:13","date_gmt":"2015-07-21T07:44:13","guid":{"rendered":"http:\/\/www.myfatblog.co.uk\/?p=944"},"modified":"2015-07-22T15:12:44","modified_gmt":"2015-07-22T14:12:44","slug":"automated-testing-of-a-provider-hosted-app-with-powershell","status":"publish","type":"post","link":"http:\/\/www.myfatblog.co.uk\/index.php\/2015\/07\/automated-testing-of-a-provider-hosted-app-with-powershell\/","title":{"rendered":"Automated testing of a Provider Hosted App with PowerShell"},"content":{"rendered":"<h1>Background<\/h1>\n<p>I was recently\u00a0 engaged to assist a client in arranging for SharePoint search results to be surfaced in a Drupal PHP based content management system. Using the excellent blog post by Kirk Evans (<a href=\"http:\/\/blogs.msdn.com\/b\/kaevans\/archive\/2014\/07\/14\/high-trust-sharepoint-apps-on-non-microsoft-platforms.aspx\">High Trust SharePoint Apps on Non-Microsoft platforms<\/a>) and some judicious use of Fiddler\/NetMon we were able to get the Drupal Application authenticating and returning search results from SharePoint.<\/p>\n<p>This post isn\u2019t about that process though as my focus was purely on the SharePoint side of the fence, so I have no idea how the Drupal team managed the JWT creation or Active Directory integration. I do know it wasn\u2019t without a significant amount of effort on their side! All I did was ensure that SharePoint was configured for apps and to create the .APP file that allowed their application request the permissions it needed. <\/p>\n<p>Instead, this post deals with one of the \u2018fine print\u2019 requirements of the engagement, and thus assumes that you already have a provider hosted app registered in your environment, which is already configured to host Apps in an on-premises scenario.<\/p>\n<p>As the Drupal website was provided and hosted by a third party, the IT team wanted to be able to test the applications connection into SharePoint in order to be able to prove a demarcation line in the event of problems in future.<\/p>\n<p>Our requirements boiled down to:-<\/p>\n<ul>\n<li>The solution needed to simulate the third party app as closely as possible<\/li>\n<li>It needed to run on a daily schedule and provide e-mail alerts<\/li>\n<li>It needed to be able to be run on-demand.<\/li>\n<\/ul>\n<p>My go to tool usually for anything like this is PowerShell in conjunction with Task Scheduler and in this case that was my chosen scenario, especially as this particular client likes to shy away from custom development that requires console apps, custom dlls or anything with a costly lifecycle.<\/p>\n<p>My initial intention was to run this in PowerShell 2.0 on a server that is provided for batch testing and the like, however I underestimated the poor certificate handling in PowerShell 2.0 which made signing the required JavaScript Web Tokens (JWT) nigh on impossible. After a good few failed attempts, I decided to break out Visual Studio and to try and unpick how the TokenHelper class that is deployed when you create a Provider Hosted App (Add-in) for SharePoint.<\/p>\n<p>This pointed me towards the System.IdentityModel.Tokens.JWT.dll that is available as a NUGet package in VS. By pulling this down to a Windows Server 2012 box and making use of PowerShell 3.0, I was able to come up with a script that lets us automate the testing of the Provider Hosted App. In the end I ran this on one of our app servers to make use of the SharePoint e-mail handling.<\/p>\n<p>In order to achieve this we will create a JWT that represents the app that has been registered in SharePoint and a suitable test account in Active Directory. This token will then be used as the Authorization Bearer token in a web request against the SharePoint Search REST Api endpoint.<\/p>\n<p>In order to do this though, we need some information that is specific to each environment in order to build the JWT. Kirk covers this really well in his <a href=\"http:\/\/blogs.msdn.com\/b\/kaevans\/archive\/2014\/07\/14\/high-trust-sharepoint-apps-on-non-microsoft-platforms.aspx\">post,<\/a> so I shall re-surface his explanation here, but credit is his for these tables.<\/p>\n<h2>Outer Token<\/h2>\n<table border=\"1\" width=\"651\" cellspacing=\"0\" cellpadding=\"2\">\n<tbody>\n<tr>\n<td valign=\"top\" width=\"96\">aud<\/td>\n<td valign=\"top\" width=\"553\">Audience.\u00a0 The value is 00000003-0000-0ff1-ce00-00000000\/<strong>&lt;hostname&gt;<\/strong>@<strong>&lt;realm*&gt;<\/strong>\u00a0 .\u00a0\u00a0\u00a0 The hostname is the FQDN of the web application root or the host-header site collection root.\u00a0 The realm is the GUID that represents the SharePoint tenant<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"96\">iss<\/td>\n<td valign=\"top\" width=\"553\">Issuer. <strong>&lt;IssuerID&gt;<\/strong>@<strong>&lt;realm*&gt;<\/strong>. The issuer ID is obtained when you register the SPTrustedIdentityTokenIssuer. The realm is the GUID that represents the SharePoint tenant.<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"96\">nbf<\/td>\n<td valign=\"top\" width=\"553\">Not before. The Unix epoch time upon which the token started being valid.<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"96\">exp<\/td>\n<td valign=\"top\" width=\"553\">Expires. The Unix epoch time upon which the token expires.<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"96\">nameid<\/td>\n<td valign=\"top\" width=\"553\">The identifier for the user (In our example an Active Directory SID value.<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"96\">actortoken<\/td>\n<td valign=\"top\" width=\"553\">The encoded and signed inner token that represents the application.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2>Inner Token<\/h2>\n<table border=\"1\" width=\"651\" cellspacing=\"0\" cellpadding=\"2\">\n<tbody>\n<tr>\n<td valign=\"top\" width=\"96\">aud<\/td>\n<td valign=\"top\" width=\"553\">Audience.\u00a0 The value is 00000003-0000-0ff1-ce00-00000000\/<strong>&lt;hostname&gt;<\/strong>@<strong>&lt;realm*&gt;<\/strong>\u00a0 .\u00a0\u00a0\u00a0 The hostname is the FQDN of the web application root or the host-header site collection root.\u00a0 The realm is the GUID that represents the SharePoint tenant<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"96\">iss<\/td>\n<td valign=\"top\" width=\"553\">Issuer.\u00a0 <strong>&lt;IssuerID&gt;<\/strong>@<strong>&lt;realm*&gt;<\/strong>.\u00a0 The issuer ID is obtained when you register the SPTrustedIdentityTokenIssuer.\u00a0 The realm is the GUID that represents the SharePoint tenant.<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"96\">nbf<\/td>\n<td valign=\"top\" width=\"553\">Not before. The Unix epoch time upon which the token started being valid.<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"96\">exp<\/td>\n<td valign=\"top\" width=\"553\">Expires. The Unix epoch time upon which the token expires.<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"96\">nameid<\/td>\n<td valign=\"top\" width=\"553\">Identifier for the app.\u00a0 <strong>&lt;Client ID&gt;@&lt;realm&gt;<\/strong>.\u00a0 The client ID uniquely identifies your app, this is provided by using AppRegNew.aspx or provided when registering an app in the Office Marketplace.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The script configures the value for all of the above, and then uses them to construct a valid JWT token that SharePoint will accept. We\u2019ll look at this in detail now.<\/p>\n<h1>The PowerShell Script<\/h1>\n<p>I\u2019ll attach the finished script at the bottom of this post, so don\u2019t worry about trying to cut and paste the segments.. download the whole thing at the end!<\/p>\n<p>The first thing our script does is pull in the various assemblies that we\u2019ll be using.<\/p>\n<pre class=\"brush: powershell; title: ; notranslate\" title=\"\">##Setup Assemblies\r\n&#x5B;System.Reflection.Assembly]::LoadWithPartialName(&quot;System.Security&quot;) | out-null\r\n&#x5B;System.Reflection.Assembly]::LoadWithPartialName(&quot;mscorlib&quot;) | out-null\r\n$identityDllPath = $PSScriptRoot + &quot;\\System.identitymodel.tokens.jwt.dll&quot;\r\nadd-type -LiteralPath $identityDllPath\r\n<\/pre>\n<p>We\u2019re using the add-type method for the System.Identitymodel.tokens.JWT.dll because this is copied from the NUGet package into the same location as the script.<\/p>\n<pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\r\n##Setup the root web and test query endpoint\r\n$rootWeb = &quot;https:\/\/sharepointsite.company.co.uk&quot;\r\n$apiInterface = &quot;\/_api\/search\/query?querytext='sharepoint'&quot;\r\n\r\n##get certificate details\r\n$privateCertPath = $PSScriptRoot + &quot;\\High-Trust-Cert.pfx&quot;\r\n$certPW = &quot;UnsecureTextPassword&quot;\r\n$certPWSecure = ConvertTo-SecureString $certPW -AsPlainText -force\r\n\r\n## set up the domain, clientid and realm.\r\n$domain = &quot;sharepointsite.company.co.uk&quot;\r\n$clientID = &quot;c9725386-972e-45d6-8996-68333dae889a&quot;\r\n$realm = Get-SPAuthenticationRealm\r\n\r\n##now setup the items we need to build the tokens\r\n$aud = &quot;00000003-0000-0ff1-ce00-000000000000\/&quot; + $domain + &quot;@&quot; + $realm\r\n$iss = $clientID + &quot;@&quot; + $realm\r\n$nameid = &quot;s-1-5-21-309554102-208957183-1128231545-40032&quot; ##This is the SID for our test account\r\n$actorNameid = $iss\r\n$nii = &quot;urn:office:idp:activedirectory&quot;\r\n$nbf = &#x5B;DateTime]::UtcNow\r\n$exp = &#x5B;DateTime]::Now.AddHours(4).ToUniversalTime()\r\n<\/pre>\n<p>With all the configuration in place, we can start to build the tokens.<\/p>\n<pre class=\"brush: powershell; title: ; notranslate\" title=\"\">##Now create a new X509 cert object with it.. this includes the Private key which allows us to Sign stuff!\r\n$cert = new-object System.Security.Cryptography.X509Certificates.X509Certificate2($privateCertPath, $certPWSecure)<\/pre>\n<p>With the certificate in place, we can get the first object that really makes our lives easier and this is an X509SigningCredentials object. We\u2019ll pass this into the JWT Token when we create it to automatically sign our Actor token to prove this is a valid app request.<\/p>\n<pre class=\"brush: powershell; title: ; notranslate\" title=\"\">##Setup the signing credentials from the certificate\r\n&#x5B;System.IdentityModel.Tokens.X509SigningCredentials] $signingCredentials = new-object System.IdentityModel.Tokens.X509SigningCredentials($cert,&#x5B;System.IdentityModel.Tokens.SecurityAlgorithms]::RsaSha256Signature, &#x5B;System.IdentityModel.Tokens.SecurityAlgorithms]::Sha256Digest)<\/pre>\n<p>With that done, we can build the Actor token (This is the Inner token that goes inside the main token).<\/p>\n<pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\r\n##############################\r\n##now build the Actor Token ##\r\n##############################\r\n&#x5B;System.IdentityModel.Tokens.JwtHeader] $jwtActorHeader = new-object System.IdentityModel.Tokens.JwtHeader($signingCredentials)<\/pre>\n<p>Note that we pass the SigningCcredentials object into the JWTHeader, this pre-configures the header to be signed. This saved me a LOT of code as we didn\u2019t have to do our own Base64URLencoding and then signing which was the realm stumbling block in PoSH 2.0.<\/p>\n<pre class=\"brush: powershell; title: ; notranslate\" title=\"\">$nameIdClaim = new-object System.Security.Claims.Claim(&quot;nameid&quot;,$actorNameid)\r\n$delegateClaim = new-object System.Security.Claims.Claim(&quot;trustedfordelegation&quot;,&quot;true&quot;)\r\n$claims = new-object 'System.Collections.Generic.List&#x5B;System.Security.Claims.Claim]'\r\n$claims.Add($nameIdClaim)\r\n$claims.Add($delegateClaim)\r\n\r\n&#x5B;System.IdentityModel.Tokens.JwtPayload] $jwtActorPayload = New-Object System.IdentityModel.Tokens.JwtPayload($iss,$aud,$claims,$nbf,$exp)<\/pre>\n<p>With the Actor Header and Actor Payload created, we can now create the full ActorToken.<\/p>\n<pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\r\n&#x5B;System.IdentityModel.Tokens.JwtSecurityToken] $jwtActorToken\u00a0 = New-Object System.IdentityModel.Tokens.JwtSecurityToken($jwtActorHeader,$jwtActorPayload)<\/pre>\n<p>And then use the JWTSecurityTokenHandler to write out the fully encoded token into a PoSH variable for inclusion in the outer token.<\/p>\n<pre class=\"brush: powershell; title: ; notranslate\" title=\"\">&#x5B;System.IdentityModel.Tokens.JwtSecurityTokenHandler] $jwtSecurityTokenHandler = new-object System.IdentityModel.Tokens.JwtSecurityTokenHandler\r\n$completeEncryptedActorToken = $jwtSecurityTokenHandler.WriteToken($jwtActorToken)<\/pre>\n<p>Now we have the actor token, we pretty much repeat the same again including the $completeEncryptedActorToken as one of the claims inside the outer JWT. This outer token is also unsigned, so we don\u2019t use the signing credentials to create the token and instead add the header values manually.<\/p>\n<pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\r\n##############################\r\n##now build the Outer Token ##\r\n##############################\r\n&#x5B;System.IdentityModel.Tokens.JwtHeader] $jwtOuterHeader = new-object System.IdentityModel.Tokens.JwtHeader\r\n$jwtOuterHeader.Add(&quot;typ&quot;,&quot;JWT&quot;)\r\n$jwtOuterHeader.Add(&quot;alg&quot;,&quot;none&quot;)<\/pre>\n<p>With the header complete, we can now create the payload.<\/p>\n<pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\r\n$outerNameIdClaim = new-object System.Security.Claims.Claim(&quot;nameid&quot;,$nameid) ##This is the SID of the person we're impersonating\r\n$outerNiiClaim = new-object System.Security.Claims.Claim(&quot;nii&quot;,$nii)\r\n$outerActorClaim = new-object System.Security.Claims.Claim(&quot;actortoken&quot;,$completeEncryptedActorToken) \r\n$outerClaims = new-object 'System.Collections.Generic.List&#x5B;System.Security.Claims.Claim]'\r\n$outerClaims.Add($outerNameIdClaim)\r\n$outerClaims.Add($outerNiiClaim)\r\n$outerClaims.Add($outerActorClaim)\r\n\r\n&#x5B;System.IdentityModel.Tokens.JwtPayload] $jwtOuterPayload = New-Object System.IdentityModel.Tokens.JwtPayload($iss,$aud,$outerClaims,$nbf,$exp)\r\n<\/pre>\n<p>For this payload, the nameid is now that of the person that we want to impersonate, so we use the SID value from Active Directory.<\/p>\n<pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\r\n##Complete the token\r\n&#x5B;System.IdentityModel.Tokens.JwtSecurityToken] $jwtOuterToken\u00a0 = New-Object System.IdentityModel.Tokens.JwtSecurityToken($jwtOuterHeader,$jwtOuterPayload)\r\n\r\n$finishedToken = $jwtSecurityTokenHandler.WriteToken($jwtOuterToken)\r\n<\/pre>\n<p>The token is now complete and $finishedToken contains the Base64URLEncoded value that you can see carried in the Bearer authorisation header in any Provider Hosted app connection to SharePoint. To use this, we merely need to make a web request against a known REST endpoint, using the token as our Bearer token in our headers.<\/p>\n<pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\r\n$webRequestURL = $rootWeb + $apiInterface\r\n$request = &#x5B;System.Net.WebRequest]::Create($webRequestURL)\r\n$request.Accept = &quot;application\/json;odata=verbose&quot;\r\n$request.Headers.Add(&quot;X-FORMS_BASED_AUTH_ACCEPTED&quot;,&quot;f&quot;)\r\n$request.Headers.Add(&quot;X-HTTP-Method&quot;, &quot;GET&quot;)\r\n$request.Headers.Add(&quot;Authorization&quot;, &quot;Bearer &quot; + $finishedToken)\r\n$request.Referer = \u201chttps:\/\/drupalsystem.companyname.co.uk\u201d<\/pre>\n<p>At this point, one of two things will happen. Either:<\/p>\n<ol>\n<li>Your request proceeds and you can continue to read the $request response stream and then go on to validate your request.<\/li>\n<li>Your token is invalid, in which case you will receive a 401 access denied.<\/li>\n<\/ol>\n<p>If you get the 401 problem, I highly recommend you fire up visual studio and load up Kirk Evan\u2019s <a href=\"http:\/\/blogs.msdn.com\/b\/kaevans\/archive\/2013\/08\/25\/creating-a-fiddler-extension-for-sharepoint-2013-app-tokens.aspx\">Fiddler4 extension for JWTs<\/a>. This great extension lets you view the contents of the JWT. The only thing it can\u2019t do is validate the certificate for you, so if the JWT looks right, then you need to focus on your certificate and ensure that you have the right one, with the private key.<\/p>\n<p><a href='http:\/\/www.myfatblog.co.uk\/wp-content\/uploads\/DrupalTest.ps1.txt'>Attached here is a text file containing the PS1 script that I used<\/a>, It\u2019s a slightly less polished version of the one that went into Live, so I will caution that it\u2019s not production ready and issued here as a training aid really.. If you break stuff with it there\u2019s no warranty. It\u2019s offered under the <a href=\"http:\/\/opensource.org\/licenses\/MIT\">MIT License<\/a>.<\/p>\n<p>I hope this post helps you if you\u2019re looking for a way to test your app infrastructure and wish you the best of luck going forward as getting this far has been hard work!<\/p>\n<p>Paul.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Background I was recently\u00a0 engaged to assist a client in arranging for SharePoint search results to be surfaced in a Drupal PHP based content management system. Using the excellent blog post by Kirk Evans (High Trust SharePoint Apps on Non-Microsoft platforms) and some judicious use of Fiddler\/NetMon we were able to get the Drupal Application &hellip; <\/p>\n<p><a class=\"more-link btn\" href=\"http:\/\/www.myfatblog.co.uk\/index.php\/2015\/07\/automated-testing-of-a-provider-hosted-app-with-powershell\/\">Continue reading<\/a><\/p>\n","protected":false},"author":2,"featured_media":949,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_exactmetrics_skip_tracking":false,"_exactmetrics_sitenote_active":false,"_exactmetrics_sitenote_note":"","_exactmetrics_sitenote_category":0,"footnotes":""},"categories":[162,110,16],"tags":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v22.3 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Automated testing of a Provider Hosted App with PowerShell - Blog of an overweight SharePoint addict<\/title>\n<meta name=\"description\" content=\"Analysis of a script to perform automated testing of High Trust Provider Hosted app infrastructure in SharePoint 2013\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"http:\/\/www.myfatblog.co.uk\/index.php\/2015\/07\/automated-testing-of-a-provider-hosted-app-with-powershell\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Automated testing of a Provider Hosted App with PowerShell - Blog of an overweight SharePoint addict\" \/>\n<meta property=\"og:description\" content=\"Analysis of a script to perform automated testing of High Trust Provider Hosted app infrastructure in SharePoint 2013\" \/>\n<meta property=\"og:url\" content=\"http:\/\/www.myfatblog.co.uk\/index.php\/2015\/07\/automated-testing-of-a-provider-hosted-app-with-powershell\/\" \/>\n<meta property=\"og:site_name\" content=\"Blog of an overweight SharePoint addict\" \/>\n<meta property=\"article:published_time\" content=\"2015-07-21T07:44:13+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2015-07-22T14:12:44+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/www.myfatblog.co.uk\/wp-content\/uploads\/2015\/07\/ScriptBlock1.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"432\" \/>\n\t<meta property=\"og:image:height\" content=\"250\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Cimares\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@cimares\" \/>\n<meta name=\"twitter:site\" content=\"@cimares\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Cimares\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"10 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"http:\/\/www.myfatblog.co.uk\/index.php\/2015\/07\/automated-testing-of-a-provider-hosted-app-with-powershell\/\",\"url\":\"http:\/\/www.myfatblog.co.uk\/index.php\/2015\/07\/automated-testing-of-a-provider-hosted-app-with-powershell\/\",\"name\":\"Automated testing of a Provider Hosted App with PowerShell - Blog of an overweight SharePoint addict\",\"isPartOf\":{\"@id\":\"http:\/\/www.myfatblog.co.uk\/#website\"},\"primaryImageOfPage\":{\"@id\":\"http:\/\/www.myfatblog.co.uk\/index.php\/2015\/07\/automated-testing-of-a-provider-hosted-app-with-powershell\/#primaryimage\"},\"image\":{\"@id\":\"http:\/\/www.myfatblog.co.uk\/index.php\/2015\/07\/automated-testing-of-a-provider-hosted-app-with-powershell\/#primaryimage\"},\"thumbnailUrl\":\"http:\/\/www.myfatblog.co.uk\/wp-content\/uploads\/2015\/07\/ScriptBlock1.jpg\",\"datePublished\":\"2015-07-21T07:44:13+00:00\",\"dateModified\":\"2015-07-22T14:12:44+00:00\",\"author\":{\"@id\":\"http:\/\/www.myfatblog.co.uk\/#\/schema\/person\/55ae8f6885bb5b8390dad001f3da83c6\"},\"description\":\"Analysis of a script to perform automated testing of High Trust Provider Hosted app infrastructure in SharePoint 2013\",\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"http:\/\/www.myfatblog.co.uk\/index.php\/2015\/07\/automated-testing-of-a-provider-hosted-app-with-powershell\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"http:\/\/www.myfatblog.co.uk\/index.php\/2015\/07\/automated-testing-of-a-provider-hosted-app-with-powershell\/#primaryimage\",\"url\":\"http:\/\/www.myfatblog.co.uk\/wp-content\/uploads\/2015\/07\/ScriptBlock1.jpg\",\"contentUrl\":\"http:\/\/www.myfatblog.co.uk\/wp-content\/uploads\/2015\/07\/ScriptBlock1.jpg\",\"width\":432,\"height\":250},{\"@type\":\"WebSite\",\"@id\":\"http:\/\/www.myfatblog.co.uk\/#website\",\"url\":\"http:\/\/www.myfatblog.co.uk\/\",\"name\":\"Blog of an overweight SharePoint addict\",\"description\":\"The rantings of a (not so) food obsessed IT consultant!\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"http:\/\/www.myfatblog.co.uk\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"http:\/\/www.myfatblog.co.uk\/#\/schema\/person\/55ae8f6885bb5b8390dad001f3da83c6\",\"name\":\"Cimares\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"http:\/\/www.myfatblog.co.uk\/#\/schema\/person\/image\/\",\"url\":\"http:\/\/www.myfatblog.co.uk\/images\/BlogImages\/About_D057\/TopOfTheWorld.jpg\",\"contentUrl\":\"http:\/\/www.myfatblog.co.uk\/images\/BlogImages\/About_D057\/TopOfTheWorld.jpg\",\"caption\":\"Cimares\"},\"sameAs\":[\"http:\/\/www.myfatblog.co.uk\"],\"url\":\"http:\/\/www.myfatblog.co.uk\/index.php\/author\/reginald\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Automated testing of a Provider Hosted App with PowerShell - Blog of an overweight SharePoint addict","description":"Analysis of a script to perform automated testing of High Trust Provider Hosted app infrastructure in SharePoint 2013","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"http:\/\/www.myfatblog.co.uk\/index.php\/2015\/07\/automated-testing-of-a-provider-hosted-app-with-powershell\/","og_locale":"en_US","og_type":"article","og_title":"Automated testing of a Provider Hosted App with PowerShell - Blog of an overweight SharePoint addict","og_description":"Analysis of a script to perform automated testing of High Trust Provider Hosted app infrastructure in SharePoint 2013","og_url":"http:\/\/www.myfatblog.co.uk\/index.php\/2015\/07\/automated-testing-of-a-provider-hosted-app-with-powershell\/","og_site_name":"Blog of an overweight SharePoint addict","article_published_time":"2015-07-21T07:44:13+00:00","article_modified_time":"2015-07-22T14:12:44+00:00","og_image":[{"width":432,"height":250,"url":"http:\/\/www.myfatblog.co.uk\/wp-content\/uploads\/2015\/07\/ScriptBlock1.jpg","type":"image\/jpeg"}],"author":"Cimares","twitter_card":"summary_large_image","twitter_creator":"@cimares","twitter_site":"@cimares","twitter_misc":{"Written by":"Cimares","Est. reading time":"10 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"http:\/\/www.myfatblog.co.uk\/index.php\/2015\/07\/automated-testing-of-a-provider-hosted-app-with-powershell\/","url":"http:\/\/www.myfatblog.co.uk\/index.php\/2015\/07\/automated-testing-of-a-provider-hosted-app-with-powershell\/","name":"Automated testing of a Provider Hosted App with PowerShell - Blog of an overweight SharePoint addict","isPartOf":{"@id":"http:\/\/www.myfatblog.co.uk\/#website"},"primaryImageOfPage":{"@id":"http:\/\/www.myfatblog.co.uk\/index.php\/2015\/07\/automated-testing-of-a-provider-hosted-app-with-powershell\/#primaryimage"},"image":{"@id":"http:\/\/www.myfatblog.co.uk\/index.php\/2015\/07\/automated-testing-of-a-provider-hosted-app-with-powershell\/#primaryimage"},"thumbnailUrl":"http:\/\/www.myfatblog.co.uk\/wp-content\/uploads\/2015\/07\/ScriptBlock1.jpg","datePublished":"2015-07-21T07:44:13+00:00","dateModified":"2015-07-22T14:12:44+00:00","author":{"@id":"http:\/\/www.myfatblog.co.uk\/#\/schema\/person\/55ae8f6885bb5b8390dad001f3da83c6"},"description":"Analysis of a script to perform automated testing of High Trust Provider Hosted app infrastructure in SharePoint 2013","inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["http:\/\/www.myfatblog.co.uk\/index.php\/2015\/07\/automated-testing-of-a-provider-hosted-app-with-powershell\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"http:\/\/www.myfatblog.co.uk\/index.php\/2015\/07\/automated-testing-of-a-provider-hosted-app-with-powershell\/#primaryimage","url":"http:\/\/www.myfatblog.co.uk\/wp-content\/uploads\/2015\/07\/ScriptBlock1.jpg","contentUrl":"http:\/\/www.myfatblog.co.uk\/wp-content\/uploads\/2015\/07\/ScriptBlock1.jpg","width":432,"height":250},{"@type":"WebSite","@id":"http:\/\/www.myfatblog.co.uk\/#website","url":"http:\/\/www.myfatblog.co.uk\/","name":"Blog of an overweight SharePoint addict","description":"The rantings of a (not so) food obsessed IT consultant!","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"http:\/\/www.myfatblog.co.uk\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-US"},{"@type":"Person","@id":"http:\/\/www.myfatblog.co.uk\/#\/schema\/person\/55ae8f6885bb5b8390dad001f3da83c6","name":"Cimares","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"http:\/\/www.myfatblog.co.uk\/#\/schema\/person\/image\/","url":"http:\/\/www.myfatblog.co.uk\/images\/BlogImages\/About_D057\/TopOfTheWorld.jpg","contentUrl":"http:\/\/www.myfatblog.co.uk\/images\/BlogImages\/About_D057\/TopOfTheWorld.jpg","caption":"Cimares"},"sameAs":["http:\/\/www.myfatblog.co.uk"],"url":"http:\/\/www.myfatblog.co.uk\/index.php\/author\/reginald\/"}]}},"_links":{"self":[{"href":"http:\/\/www.myfatblog.co.uk\/index.php\/wp-json\/wp\/v2\/posts\/944"}],"collection":[{"href":"http:\/\/www.myfatblog.co.uk\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.myfatblog.co.uk\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.myfatblog.co.uk\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/www.myfatblog.co.uk\/index.php\/wp-json\/wp\/v2\/comments?post=944"}],"version-history":[{"count":18,"href":"http:\/\/www.myfatblog.co.uk\/index.php\/wp-json\/wp\/v2\/posts\/944\/revisions"}],"predecessor-version":[{"id":964,"href":"http:\/\/www.myfatblog.co.uk\/index.php\/wp-json\/wp\/v2\/posts\/944\/revisions\/964"}],"wp:featuredmedia":[{"embeddable":true,"href":"http:\/\/www.myfatblog.co.uk\/index.php\/wp-json\/wp\/v2\/media\/949"}],"wp:attachment":[{"href":"http:\/\/www.myfatblog.co.uk\/index.php\/wp-json\/wp\/v2\/media?parent=944"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.myfatblog.co.uk\/index.php\/wp-json\/wp\/v2\/categories?post=944"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.myfatblog.co.uk\/index.php\/wp-json\/wp\/v2\/tags?post=944"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}