tag:blogger.com,1999:blog-56344416415138795772024-02-19T02:00:54.848-08:00SharePointersA blog dedicated to the exploration and development of Microsoft SharePoint.Paulhttp://www.blogger.com/profile/05424579499113928113noreply@blogger.comBlogger121125tag:blogger.com,1999:blog-5634441641513879577.post-42699136182923247492023-10-09T13:48:00.000-07:002023-10-09T13:48:43.039-07:00Set up Enterprise App to use App-Only Sites.Selected permissions and wite to SharePoint with PnP Powershell<p>I wanted to run unattended scripts against SharePoint for various governance and content cleanup jobs and found the guidance for this to be a little confusing. I think it's a good idea to limit the access of any script, so I prefer to set up an App per script and use the Sites.Selected permission to limit the sites to which my app has access. Here's the process I used to get it to work:<br /><br />You can register an app in the Azure portal UI, but there's a few steps that must be performed with PowerShell, so I figured just doing it all in Powershell made it consistent. </p><h2 style="text-align: left;">Step 0: Get the right version of PnP.Powershell</h2><p>I also had to use the PnP.PowerShell 2.2.81 nightly build because there was a bug introduced in 2.2.0. If you need to get a specific version you can run Install-Module, <b>but I prefer to use Save-Module with specific version</b> so I can keep different version of PnP.PowerShell around to avoid having my old scripts affected by new modules and potential regression issues. <br /><br />Once you have the right version, run the following line (or include in your script file):</p><p>Import-Module D:\psbin\PnP.PowerShell\2.2.81\PnP.PowerShell.psd1</p><h2 style="text-align: left;">Step 1: Register the App</h2><div>In this step we'll do the one time app registration with a certificate, then we'll give the App Sites.Selected WRITE permission (your only choice when doing the initial grant is READ|WRITE). Immediately after, we update the permissions with FullControl, as this is required to upload files.</div><h4>Permissions Needed: Global Administrator/Azure AD Admin</h4><div>In my Dev tenant this is no problem since I have this right. In prod environments I don't typically have this right so I would plan to hand this script or the steps off to one of my admins.</div><div><br /></div><h3 style="text-align: left;">Generate Certificate</h3><div>You'll need to use a certificate to authenticate with your app. In this example I am testing against my developer tenant. I'm using a self-signed cert, but you can be more secure and use one created by a trusted CA. If you go the trusted CA route, you can skip to the registration</div><p><span style="font-family: courier;">$pw = "USEAGOODPASSWORD" #this is not a good password....</span></p><p><span style="font-family: courier;">$commonName = 'EAUpload'</span></p><p><span style="font-family: courier;">$certificateName = "EASharePointSiteUpload_TEST"</span></p><p><span style="font-family: courier;">$certFile = "$certificateName.cer"</span></p><p><span style="font-family: courier;">$certPfx = "$certificateName.pfx"</span></p><p><span style="font-family: courier;">$certPass = (ConvertTo-SecureString -String $pw -AsPlainText -Force)</span></p><p><span style="font-family: courier;">New-PnPAzureCertificate -CommonName $commonName -OutPfx "$certPfx" -OutCert "$certFile" -CertificatePassword $certPass</span></p><h3 style="text-align: left;">Register the App with a Certificate</h3><div>Make sure to update the script to replace YOURTENANT then run</div><p><span style="font-family: courier;"># SETUP</span></p><p><span style="font-family: courier;">$hostUrl = "https://YOURTENANT.sharepoint.com"</span></p><p><span style="font-family: courier;">$hostRelativeUrl = "/sites/EAUploadTest" #change to whatever site you want the app to work with</span></p><p><span style="font-family: courier;">$siteUrl = "$hostUrl$hostRelativeUrl"</span></p><p><span style="font-family: courier;">$appName = "EAUploadTestApp_TEST"</span></p><p><span style="font-family: courier;">$tenant = "YOURTENANT.onmicrosoft.com"</span></p><p><span style="font-family: courier;"># END SETUP</span></p><p><span style="font-family: courier;">Write-Host "Registering App on $siteUrl"</span></p><p><span style="font-family: courier;">Connect-PnPOnline $siteUrl -Interactive</span></p><p><span style="font-family: courier;">$reg = Register-PnPAzureADApp -ApplicationName $appName `</span></p><p><span style="font-family: courier;"> -Tenant $tenant `</span></p><p><span style="font-family: courier;"> -CertificatePath $certPfx `</span></p><p><span style="font-family: courier;"> -CertificatePassword $certPass `</span></p><p><span style="font-family: courier;"> -GraphApplicationPermissions "User.Read.All" `</span></p><p><span style="font-family: courier;"> -SharePointApplicationPermissions "Sites.Selected" `</span></p><p><span style="font-family: courier;"> -Interactive</span></p><p><span style="font-family: courier;">Write-Host "Granting WRITE permissions to app on: $siteUrl"</span></p><p><span style="font-family: courier;">$grant = Grant-PnPAzureADAppSitePermission -Permissions Write -Site $siteUrl -AppId "PUTAPPIDHERE" -DisplayName "MYAPP_SITESSELECTED_FULL"</span></p><p><span style="font-family: courier;">$reset = Set-PnPAzureADAppSitePermission -PermissionId $grant.Id -Permissions FullControl</span></p><p><span style="font-family: courier;">Disconnect-PnPOnline</span></p><h2 style="text-align: left;">Step 2: Allow NoScript on the SP Site</h2><div>I couldn't figure out any way around this, seems that a site has to have NoScript disabled in order to allow api uploads.</div><h4 style="text-align: left;">Permissions Needed: SP Admin</h4><div><span style="font-family: courier;">Connect-PnPOnline $siteUrl -Interactive</span></div><p><span style="font-family: courier;">Write-Host "Setting NoScript to FALSE (so we can do file uploads)"</span></p><p><span style="font-family: courier;">Set-PnPSite -NoScriptSite $false</span></p><p><span style="font-family: courier;">Write-Host "Disconnecting from Admin (User) Credentials"</span></p><p><span style="font-family: courier;">Disconnect-PnPOnline</span></p><p><br /></p><h2 style="text-align: left;">Step 3: Test with App-Only Credentials</h2><p>Here we connect with only App credentials (not user credentials).</p><p><span style="font-family: courier;">Write-Host "Connecting with App Credentials"</span></p><p><span style="font-family: courier;">Connect-PnPOnline -Url $siteUrl -ClientId $reg.'AzureAppId/ClientId' -Tenant $tenant -CertificatePath $certPfx -CertificatePassword $certPass #-ThumbPrint $reg.'Certificate Thumbprint' </span></p><p><span style="font-family: courier;">Write-Host "--Saving File"</span></p><p><span style="font-family: courier;">$testFile = 'testFile.txt' </span></p><p><span style="font-family: courier;">Add-PnPFile -Path $testFile -Folder "$hostRelativeUrl/Shared Documents/"</span></p><p><span style="font-family: courier;">Write-Host "--Disconnecting from App Credentials"</span></p><p><span style="font-family: courier;">Disconnect-PnPOnline</span></p>Paulhttp://www.blogger.com/profile/05424579499113928113noreply@blogger.com0tag:blogger.com,1999:blog-5634441641513879577.post-52260968388456855052021-08-23T12:10:00.002-07:002021-08-23T12:10:56.269-07:00 Quick SPFx Dev Environment Setup Guide<p><br /></p><p>This is just a quick post to document my current setup steps</p><p></p><ol style="text-align: left;"><li>Install NVM for windows</li><li>Install the proper version(s) of node using nvm install <i>VersionNum (see https://docs.microsoft.com/en-us/sharepoint/dev/spfx/set-up-your-development-environment for currently supported versions)</i></li><li>Address any critical vulnerabilities</li><li>Install yeoman and spfx genereator</li><ol><li>npm i -g yo</li><li>npm i -g @microsoft/generator-sharepoint</li></ol><li>Install additional utils</li><li>Install gulp</li><ol><li>npm i -g gulp</li></ol><li>Install Git</li><li>Install VS COde</li><li>Test yo @microsoft/sharepoint</li></ol><p></p><p><br /></p>Paulhttp://www.blogger.com/profile/05424579499113928113noreply@blogger.com0tag:blogger.com,1999:blog-5634441641513879577.post-45581334967092443712021-02-25T08:49:00.005-08:002021-02-26T10:19:29.675-08:00Show Document LIbrary from another site collection on a Modern SharePoint Page<p>Here's a pretty good workaround for the lack of a cross-Site Collection Document library and not having to go to a fancy search interface or develop or buy an SPFx component. Keep in mind that the user who's visiting the site where you're surfacing the library will need at least read access to the library.</p><p></p><ol style="text-align: left;"><li>Go to the document library you'd like to surface, then go to the folder, etc. with the information you'd like to share.</li><li>Copy the URL from the address bar.</li><li>On the Modern Page/site where you'd like to show that document library/folder, add an Embed Web Part</li><li>Add the following to your embed web part:<br /><span style="font-family: courier;"><iframe src="URLYOUCOPIEDINSTEP1" width="100%" height="600"></iframe></span></li></ol><p></p><p>This experience allows people to navigate the library/folders without leaving the site they are on, but the docs open in their own tab.</p>Paulhttp://www.blogger.com/profile/05424579499113928113noreply@blogger.com0tag:blogger.com,1999:blog-5634441641513879577.post-70049157698874611432021-01-11T10:15:00.001-08:002021-01-11T10:15:33.721-08:00Power Automate: Using the SharePoint Update Item action<p>Power Automate's Update Item action for SharePoint has an issue with choice fields in that when you add that action, all fields are blank EXCEPT Choice fields. Choice fields will instead default to the top item in the choice list. This is really bad because if you don't clear them the flow will overwrite any existing values with the top items.</p><p>Currently, the only way I can see to avoid this issue is to manually clear each field, so here are the steps:</p><p></p><ol style="text-align: left;"><li>Choose the dropdown item on the choice field.</li><li>Choose "Enter Custom Value"</li><li>Immediate go back to the field and click the 'X' in the field and it will be cleared</li><li>Repeat for each choice field that you don't want to change.</li></ol><div><br /></div><div>I think the above is just a hack/workaround to a problem with how this action is configured by default so I put this into the uservoice/suggestion box for PowerAutomate. Upvote this if you think it's worth it:</div><div><br /></div><div>https://powerusers.microsoft.com/t5/Power-Automate-Ideas/SharePoint-Update-Item-on-Choice-Fields-default-value-overrides/idi-p/790698</div><div><br /></div><p></p>Paulhttp://www.blogger.com/profile/05424579499113928113noreply@blogger.com0tag:blogger.com,1999:blog-5634441641513879577.post-19438442236603162382019-03-28T13:14:00.002-07:002019-03-28T13:39:55.188-07:00Restoring a lot of files from the Recycle BinI had a customer who accidentally synched a (very large) SP Online library and then decided they didn't want the files on their PC anymore...so they deleted them and were shocked to learn that they'd been deleted from SharePoint too!<br />
<br />
Thanks to PnP Powershell you can use the following to restore a batch of files quickly (and filter).<br />
<br />
First, you'll want to make sure you only select the files you want to restore. I used a combination of filtering by the person who deleted the files and the date they were deleted, e.g.<br />
<br />
<div class="code">
Connect-PnPOnline https://yourtenanturl<br />
<br />
$restoreSet = Get-PnPRecycleBinItem | Where-Object { $_.DeletedByEmail -eq "imsorry@company.com" -and $_.DeletedDate -gt "1/1/2019" }</div>
<br />
<br />
Make sure you have a fairly updated version of the PnP Powershell module as the objects that come back have more properties populated than in older versions so you can do more powerful filtering<br />
<br />
Next you can restore the files like this:<br />
<br />
<div class="code">
$restoreSet | Restore-PnPRecycleBinItem -Force</div>
<br />
<br />
Use the -Force parameter unless you like hitting the "Y" key (a lot).<br />
<br />
<br />Paulhttp://www.blogger.com/profile/05424579499113928113noreply@blogger.com0tag:blogger.com,1999:blog-5634441641513879577.post-63608811437090012712018-06-14T09:01:00.001-07:002018-06-14T09:15:22.635-07:00Scoped Bootstrap for SharePointI've got a project for a client that involves refactoring a lot of bad choices related to SharePoint branding in Classic mode sites. (While I'm enthusiastic about the Modern Sites and new techniques using SPFx extensions, most of our customers are slow on the uptake).<br />
<br />
I've had to do this a few times and <a href="https://melcher.it/2016/03/bootstrap-sharepoint-online-avoid-css-ricochet/" target="_blank">this blog</a> explains it perfectly, but due to some formatting issues over there and a desire for just the steps as I need to update/repeat this, I've summarized here:<br />
<br />
<br />
<ol>
<li>Open up a node capable command prompt (I use cmd)</li>
<li>Create a directory for your solution (e.g. C:\Repos\ScopedBootstrap)</li>
<li>Run <b>npm install bootstrap@3.3.7</b> (or whatever version you need to work with)</li>
<li>Go into the node_modules\bootstrap\less directory </li>
<li>Open bootstrap.less in VS Code.</li>
<li>Place .YourUniqueClassName{ before all the @import statements and close the curly brace at the end of the file.</li>
<li>Go back to the ..\bootstrap directory (in node_modules)</li>
<li>Run <b>npm install </b>to install the dependencies</li>
<li>Run<b> grunt dist</b></li>
<li>Go to the node_modules\bootstrap\dist\css directory in the project and grab the css file you need. If you open it you should see YourUniqueClassName appended to each seletor. </li>
<li>Once you reference this file it allows you to enable bootstrap at a certain level of the DOM simply by including .YourUniqueClassName in any elements that need it. You can do it at a parent node level to affect everything else in the tree below.</li>
</ol>
<div>
<br /></div>
<div>
<br /></div>
Paulhttp://www.blogger.com/profile/05424579499113928113noreply@blogger.com0tag:blogger.com,1999:blog-5634441641513879577.post-13241122679582536132018-03-15T07:58:00.001-07:002019-06-20T13:23:00.370-07:00Switching between on-prem and SharePoint Online versions of PnP Powershell CommandsI've updated my original post to just link to these instructions. This is a better way of doing it as you're explicitly loading the specific commands each time you need to run them, that way you're clear on which version you're using:
<a href="https://www.erwinmcm.com/running-the-various-versions-of-pnp-powershell-side-by-side/" target="_blank">https://www.erwinmcm.com/running-the-various-versions-of-pnp-powershell-side-by-side/ </a><br />
<br />
<br />
<strike><span style="color: #cccccc;"> I use the PnP Powershell commands very frequently, but mostly only for SP Online. Lately I've been working on a SP2013 customization and wanted to use the PnP PowerShell commands for SP2013.</span></strike><br />
<br />
<strike><span style="color: #cccccc;">If you have multiple version of the commands installed then you'll need to select which one you want to use.</span></strike><br />
<strike><span style="color: #cccccc;"><br /></span></strike>
<strike><span style="color: #cccccc;">This thread explains that you need to clear your PSMODULEPATH environment variables but then you'll need to an import-module when you need to work with a particular version. Follow this guidance first: https://github.com/SharePoint/PnP-PowerShell/issues/1356</span></strike><br />
<strike><span style="color: #cccccc;"><br /></span></strike>
<strike><span style="color: #cccccc;">Doing that is fine if you don't mind retyping your module path in the import, but doing it by friendly name is probably easier</span></strike><br />
<strike><span style="color: #cccccc;"><br /></span></strike>
<strike><span style="color: #cccccc;">Here's a quick PS command that saves you from having to manually type in the installation path:</span></strike><br />
<strike><span style="color: #cccccc;"><b><br /></b>
<b>Get-Module <span style="color: red;">SharePointPnPPowerShell2013</span> -ListAvailable | Select Path | % { Import-Module $_.Path }</b></span></strike><br />
<strike><span style="color: #cccccc;"><br /></span></strike>
<strike><span style="color: #cccccc;">Just swap the SharePointPnPPowerShell2013 (<span style="color: red;">in red</span>) for SharePointPnPPowerShell2016 or SharePointPnPPowerShellOnline based on your needs.</span></strike><br />
<strike><span style="color: #cccccc;"><br /></span></strike>
<strike><span style="color: #cccccc;">Also, if you have multiple versions of the same module, you can specify which version you want to load in the Import-Module command's -RequiredVersion parameter. E.g.:</span></strike><br />
<strike><span style="color: #cccccc;"><br /></span></strike>
<b><strike><span style="color: #cccccc;">Get-Module <span style="color: red;">SharePointPnPPowerShell2013</span> -ListAvailable | Select Path | % { Import-Module $_.Path -RequiredVersion <span style="color: red;">2.24.1803</span> }</span></strike></b><br />
<strike><span style="color: #cccccc;"><b><br /></b>
If you aren't sure what flavor/versions of the commands you have simply run the first command in the pipeline with a wildcard in the module name:</span></strike><br />
<strike><span style="color: #cccccc;"><br /></span></strike>
<b><strike><span style="color: #cccccc;">Get-Module <span style="color: red;">SharePointPnPPowerShell*</span> -ListAvailable</span></strike></b><br />
<br />Paulhttp://www.blogger.com/profile/05424579499113928113noreply@blogger.com0tag:blogger.com,1999:blog-5634441641513879577.post-2024322550038784072017-11-08T10:58:00.002-08:002017-11-08T11:01:12.970-08:00Client Side Override the Site Logo's link in an SharePoint SiteIn SharePoint sites that have any kind of hierarchy of subwebs, it is frequently desirable to override the logo's link behavior to link back to the root of the site collection. There's a bunch of guidance on how to do this by overriding the master page, but not much on how to do this client-side, to avoid MasterPage manipulation. Here's a script that helps to do this:<br />
<br />
<span style="color: #38761d; font-family: Courier New, Courier, monospace;">//update site icon link, SP overrides any direct reassignment so you have to change the existing ID</span><br />
<span style="color: #38761d; font-family: Courier New, Courier, monospace;">//and then create a dummy element with the existing ID to avoid future JS errors.</span><br />
<span style="font-family: Courier New, Courier, monospace;"><span style="color: #38761d;">//read old link id</span></span><br />
<span style="font-family: Courier New, Courier, monospace;">var prevId = $("#DeltaSiteLogo > a").attr('id');</span><br />
<span style="font-family: Courier New, Courier, monospace;">//change the id</span><br />
<span style="font-family: Courier New, Courier, monospace;">$("#" + prevId).attr({</span><br />
<span style="font-family: Courier New, Courier, monospace;"> 'id':'CustomSiteLogo',</span><br />
<span style="font-family: Courier New, Courier, monospace;"> 'title': 'Employee Portal Home',</span><br />
<span style="font-family: Courier New, Courier, monospace;"> 'href':window.location.protocol + "//" + window.location.host</span><br />
<span style="font-family: Courier New, Courier, monospace;">});</span><br />
<span style="font-family: Courier New, Courier, monospace;">$("#DeltaSiteLogo > a").after("<a id='" + prevId + "' href='#' style='display:none'>Dummy</a>"</span><span style="font-family: "Courier New", Courier, monospace;">);</span><br />
<br />
You'll need jQuery to do this and I'd recommend putting this into a file and then injecting via a SiteCollection scope custom action. Here's the simplest way to do that:<br />
<br />
<a href="https://github.com/SharePoint/PnP-PowerShell/blob/master/Documentation/Add-PnPCustomAction.md" target="_blank">https://github.com/SharePoint/PnP-PowerShell/blob/master/Documentation/Add-PnPCustomAction.md </a>Paulhttp://www.blogger.com/profile/05424579499113928113noreply@blogger.com1tag:blogger.com,1999:blog-5634441641513879577.post-13721615335616859182017-03-29T09:44:00.000-07:002017-03-29T09:44:07.398-07:00Connect-PnPOnline : For security reasons DTD is prohibited in this XML document. errorUntil today I had never received this error when trying to connect to SPO. If you get this error there's a good chance it's related to missing records on the DNS server your machine is relying upon. If not set, there's a good chance you're using your ISP's DNS servers, whose records may not be as up to date as others. The quick fix (at least for me) was to alter my DNS settings to point to more reliably up-to-date DNS. Here's a how to fix this issu (on Windows 10, if you aren't using windows 10, follow your OS instructions on updating DNS settings and then just jump to step 4 below) along with a few options for DNS settings that I tested:<br />
<br />
<br />
<ol>
<li>Click Start and type "View Network Connections.</li>
<li>Right-Click your adapter that connects to the internet and choose properties</li>
<li>Choose TCP/IP v4 and then click the "Properties" button</li>
<li>At the bottom of the IP v4 properties window, select the radio button that says "Use the following DNS Server addresses" and enter in a primary and secondar DNS.</li>
<ol>
<li>You can view a recently updated list of options here: <a href="https://www.lifewire.com/free-and-public-dns-servers-2626062">https://www.lifewire.com/free-and-public-dns-servers-2626062</a> </li>
<li>FWIW,<b> I chose Google's, Primary: 8.8.8.8 and Secondary: 8.8.4.4</b></li>
</ol>
<li>Click OK out of all the windows and retry the Connect-PnP (or Connect-SPO) command.</li>
</ol>
<div>
<br /></div>
Paulhttp://www.blogger.com/profile/05424579499113928113noreply@blogger.com0tag:blogger.com,1999:blog-5634441641513879577.post-51287321460912440042016-08-15T20:25:00.002-07:002016-08-15T20:26:00.394-07:00Reordering the default content type for document setsHad a particularly annoying time with this as the document sets were already in use and was attempting to do this in SharePoint Online. My scenario was that I was using document sets and only wanted document sets in the root folder. So I set the other ctypes as not visible, but then the customer asked to default to one of the content types that wasn't previously set up at the top of the list, and I couldn't reorder in the "Document Set Setting" option of the document set content type because there's a multi-select box with no up/down functionality for these. As a last ditch effort I went back to the List Settings and just made all content types visible on the new button, which enabled the documents that were supposed to created in the document set to be created at the root level (temporarily). Then I reordered the content types, then set the non-docset content types back to not being visible. VOILA! to my surprise that solved the problem. <br />
<br />
I had previously tried to reorder them but I didn't make them visible first and it didn't work. <br />
<br />
Hope this helps someone else spend less time scratching their head.Paulhttp://www.blogger.com/profile/05424579499113928113noreply@blogger.com1tag:blogger.com,1999:blog-5634441641513879577.post-7049811062326133232014-09-18T12:46:00.001-07:002014-09-19T11:15:33.966-07:00Setting up an SP2013 VM on Azure, with a GUID-less DB<ol><ol><ol>
<li><div style="font-weight: normal;">
Critical Path Training produces a number of excellent training courses, books, and free resources. If you haven't checked out their <a href="http://www.amazon.com/gp/product/0735674477/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0735674477&linkCode=as2&tag=sharep03-20&linkId=3MEHRRH42ADCCB3Y" target="_blank">Inside SharePoint 2013</a> book, you definitely should. It's a pretty comprehensive guide to what Developers need to know (initially) to do SP2013 Development.</div>
<div style="font-weight: normal;">
<br /></div>
<div>
<div style="font-weight: normal;">
I typically build their VM when I first start using the next version of SharePoint and often make it my baseline for general development. This year however I've decided to spice it up a bit and go for an install without the Configuration Wizard and a GUID-less database instance, per <a href="http://www.amazon.com/gp/product/1118495810/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1118495810&linkCode=as2&tag=sharep03-20&linkId=R7ZYFPVXBZRBRERV" target="_blank">Todd Klindt/Shane Young's book</a> because their guide is more close to an enterprise level configuration. I also wanted install and configure it in Azure, so I can get to it wherever I am (and free up some <a href="http://www.amazon.com/gp/search/ref=as_li_qf_sp_sr_tl?ie=UTF8&camp=1789&creative=9325&index=aps&keywords=ssd&linkCode=ur2&tag=sharep03-20&linkId=7FOK6KGR4RQ3QX4U" target="_blank">SSD</a><img alt="" border="0" src="http://ir-na.amazon-adsystem.com/e/ir?t=sharep03-20&l=ur2&o=1" height="1" style="border: none !important; margin: 0px !important;" width="1" /> space on my PC). </div>
<div style="font-weight: normal;">
<br /></div>
<div style="font-weight: normal;">
The Critical Path VM guide can be downloaded <a href="http://www.criticalpathtraining.com/members/" target="_blank">here</a>. You'll need a (free) account to download the guide. I suggest you read through the guide to get a good sense of what you'll be doing (and how much goes into building a VM - the key reason why I want it built and backed up in the cloud, redoing this is a time consuming process.) After you've read the guide, if you want to build it in Azure, with GUID-less DBs, then hopefully my experience will help you.</div>
<div style="font-weight: normal;">
<br /></div>
<div style="font-weight: normal;">
The Critical Path VM guide version I used is Version 3.0, written by Gary Lapointe (who is a Powershell master and also wrote an excellent <a href="http://www.amazon.com/gp/product/0470939206/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0470939206&linkCode=as2&tag=sharep03-20&linkId=RDKGXWQM6FZ3YF74" target="_blank">book</a> for SP2010). I put items in <b>bold text</b> when I'm either straying from or returning to the Critical Path guide (hereafter referred to as the CP Guide).</div>
<div style="font-weight: normal;">
<br /></div>
<div style="font-weight: normal;">
<br /></div>
<div style="font-weight: normal;">
<br /></div>
<ol>
<li style="font-weight: normal;"><b>Log in to Azure</b></li>
<li style="font-weight: normal;">Click "Networks" and create a new Virtual Network, you just have to give it a name, don't worry about the DNS, VPN, or subnet stuff</li>
<li style="font-weight: normal;">Click Virtual Machines and create a new Windows Server 2012 R2 Datacenter VM (from the Gallery)</li>
<ol style="font-weight: normal;">
<li>Give it a name</li>
<li>Choose the A4 "Size" and create a new user (Admin and Administrator are reserved, so I use Local_Admin)</li>
<li>On the next page, you can either create a new cloud service or use an existing one. Your choice</li>
<li>For the Region, choose the Virtual Network you created in step 2</li>
<li>Leave storage and Availability sets as thConeir default, then choose the next arrow.</li>
<li>Remote desktop to the new VM. Click Start > Run > mstsc and click enter and enter in the DNS name for your new VM (Listed in the table of your VMs in Azure)</li>
<li>NOTE: The Critical Path guide suggest creating 2 Networks/NICs for your VM but as far as I was able to tell this is not yet supported, so you have to go with only one<b>.</b></li>
</ol>
<li style="font-weight: normal;">At this point you can <b>get back to the CP guide</b>, just find the section where the installation of Windows finishes up.</li>
<ol>
<li style="font-weight: normal;">You can skip the rename the PC part, so long as you like the name you set up in Azure initially</li>
<li style="font-weight: normal;">Do the Disable Enhanced security Config (ESC) steps.</li>
<li style="font-weight: normal;">Do the Firewall Steps</li>
<li style="font-weight: normal;">Skip the Remote Desktop step (you're already remoted in...)</li>
<li style="font-weight: normal;">Do the step where you set the Admin password to never expire</li>
<li style="font-weight: normal;"><b>Skip the networking section (both internal and external) </b>and simply test your network connection by opening IE and browsing to an external site like www.bing.com</li>
<li style="font-weight: normal;"><b>Enable the Desktop Experience per the guide (NOTE you'll need to click next a few times to get to the Features selection, the guide makes this seem like you can go straight to Features).</b></li>
<li style="font-weight: normal;">Do the windows updates per the guide</li>
<li style="font-weight: normal;"><b>Skip the Windows Activation (should already be activated)</b></li>
<li style="font-weight: normal;"><b>Do the Active Directory Configuration Task per the CP guide</b></li>
<li style="font-weight: normal;"><b>Start the SQL Server Installation</b></li>
<ol style="font-weight: normal;">
<li>Skip the DVD mouting directions and just open up IE and download the SQL Server 2012 R2 ISO from MSDN, then open the downloaded ISO and it should mount as your E: drive</li>
<li>Click the setup.exe file and then resume the Critical Path guidance</li>
<li>After SQL is installed:</li>
<ol>
<li>Continue with the SQL Configuration per the document</li>
<li><b>[optional, but recommended] Set the Max Degrees of Parallelism on SQL to 1.]</b></li>
<ol>
<li>On your VM start SQL Management Studio and connect to your SharePoint SQL Instance (should be your local server in this case)</li>
<li>Once connected to the SQL Instance right click on the Instance name and choose "Properties" from the context menu, then choose the "Advanced" page.</li>
<li>On the Advanced page, scroll down to the Parallelism category and set Max Degrees of Parallelism to 1 (from the default of 0). Then click OK.</li>
</ol>
<li><b>You can optionally install the AdventureWorks data, but if you're new to SP and intend to mess around with BI stuff, it's probably a good idea. (note you can do this later if you wish)</b></li>
</ol>
</ol>
<li style="font-weight: normal;">Continue with the file downloads</li>
<li style="font-weight: normal;">Continue with creating the Service accounts with Script01 (for DNS) and Script02 (for creating users)</li>
<li style="font-weight: normal;">Continue by installing the SharePoint prerequisites</li>
<li style="font-weight: normal;">Continue with SharePoint installs</li>
<li style="font-weight: normal;">Continue with addition </li>
<ol style="font-weight: normal;">
<li>Install the C++ redistributable package</li>
<li>Download the Web Platform installer</li>
<ol>
<li>Install the Service Bus 1.0 and CU</li>
<li>Install the Workflow Manager 1.0 Refresh</li>
</ol>
</ol>
<li style="font-weight: normal;"><b>At this point you now (may) want to stop using the guide so we can do an install without the configuration wizard. I'll be using the guidance that was provided by <a href="http://www.amazon.com/gp/product/1118495810/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1118495810&linkCode=as2&tag=sharep03-20&linkId=R7ZYFPVXBZRBRERV" style="font-weight: normal;" target="_blank">Todd Klindt/Shane Young's book</a> in chapter 3 for this.</b></li>
<li style="font-weight: normal;">Do the Initial Setup of farm</li>
<ol style="font-weight: normal;">
<li>Open the SharePoint Management Shell as an Administrator (run as Administrator)</li>
<ol>
<li>Type the following command to set up the farm and Central Admin:<br /><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">New-SPConfigurationDatabase -DatabaseName SharePoint_Config -DatabaseServer YOURSERVERNAME -AdministrationContentDatabaseName SharePoint_Admin_Content</span></li>
<li>You'll first be prompted for a username and password. Enter your SP_Farm account here (if you followed the CP guidance your password is "Password1")</li>
<li>You'll be prompted to provide a farm passphrase. To stay consistent with the CP Guidance, use "Password1"</li>
<li>You'll wait a few minutes for the command to finish running (it seemed like about 10 for me, so be patient).</li>
</ol>
<li>Next, launch the SharePoint Configuration Wizard.</li>
<ol>
<li>You should be able to just click next through this, but make sure you choose a port number that you can remember.</li>
<li>After the wizard completes you should be directed to Central Admin and asked if you want to participate in the customer experience program</li>
</ol>
</ol>
<li style="font-weight: normal;">Set up your farm's Core Services</li>
<ol>
<li style="font-weight: normal;">On the first page it asks you to either "Start the Wizard" or "Cancel" (you'll configure things yourself). We want to configure everything ourselves and use Powershell whenever it's the better option, so click "Cancel"</li>
<li style="font-weight: normal;">Set up a few Managed Accounts</li>
<ol style="font-weight: normal;">
<li>Go to Security > General Security > Configure managed accounts</li>
<li>Verify that SP_Farm is already listed as a Managed Account</li>
<li>Set up your SP_Services (will be used as the app pool, service identity, etc for the Service Applications) account as a managed account</li>
<ol>
<li>Click Register Managed Account</li>
<li>Enter in DOMAIN\SP_Services (where DOMAIN is your domain WINGTIP if you've stuck with CP) and then enter the Password</li>
<li>Ignore everything else and click OK</li>
<li>Verify that you see SP_Services listed in the Managed Accounts list</li>
</ol>
<li>Repeat step 3, above, for SP_Content (will be used as the app pool account for the content applications)</li>
</ol>
<li style="font-weight: normal;">Set up your service application pool</li>
<ol style="font-weight: normal;">
<li><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">New-SPServiceApplicationPool -Name "Default SharePoint Service App Pool" -Account [YOURDOMAIN\YOURSERVICEACCOUNT]</span><br />where YOURDOMAIN is your domain (duh, in the CP guide it's WINGTIP) and your service account is the account you created for you SharePoint service applications (SP_Services if you're following the CP guide).</li>
<li>Once you execute this command, you may want to see the new app pool in IIS, but <u>don't bother because you wont see it until you associate a service application with this app pool</u>.</li>
</ol>
<li style="font-weight: normal;">Provision the state service by executing the following lines (press enter after each line)</li>
<ol style="font-weight: normal;">
<li><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">New-SPStateServiceApplication -Name "State Service Application"</span></li>
<li><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">Get-SPStateServiceApplication | New-SPStateServiceApplicationProxy -defaultproxygroup</span></li>
<li><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">Get-SPStateServiceApplication | New-SPStateServiceDatabase -Name "State_Service_DB"</span></li>
<li><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">Get-SPDatabase | Where-Object {$_type -eq "Microsoft.Office.Server.Administration.StateDatabase"} | Initialize-SPStateServiceDatabase</span></li>
</ol>
<li style="font-weight: normal;">Provision Usage and Health Data by executing the following lines (press enter after each line)</li>
<ol style="font-weight: normal;">
<li><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">New-SPUsageApplication -Name "Usage and Health Data Collection"</span></li>
<li><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">$proxy = Get-SPServiceApplicationProxy | where {$_.TypeName -eq "Usage and Health Data Collection Proxy"}</span></li>
<li><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">$proxy.Provision();</span></li>
</ol>
<li style="font-weight: normal;"><b>The CP Guide suggests turning on these services via the Wizard, I've used <strike>strikethrough</strike> the ones we configured already in the previous steps (then I'll talk about how to configure the remaining ones). If you don't feel like you need to turn on some of the services right away, feel free to skip those steps.</b></li>
<ol style="font-weight: normal;">
<li>App Management Service</li>
<li>Business Data Connectivity Service</li>
<li>Excel Services</li>
<li><span style="color: red;"><strike>Machine Translation </strike>(I'm skipping this one because I don't think I'll need it for a while)</span></li>
<li>Managed Metadata</li>
<li>PowerPoint Conversion</li>
<li>Secure Store</li>
<li><strike>State Service</strike></li>
<li><strike>Usage and Health Data Collection</strike></li>
<li>Visio Graphics Service</li>
<li>Word Automation Services</li>
<li>Work Management Service Application - this Service App depends on the Search Service and the User Profile Service, so we'll be configuring those here as well so the order will actually be</li>
<ol>
<li>User Profile Service</li>
<li>Search Service</li>
<li>Work Management Service</li>
</ol>
<li>Workflow Service Application</li>
</ol>
<li>Set up the App Management Service. This involves configuring the subscription service app, so we'll do this too.</li>
<ol>
<li style="font-weight: normal;">Setup up the Subscriptions Service App</li>
<ol style="font-weight: normal;">
<li>Open the SP Powershell and type the following (then press Enter)<br /><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">$svcapp = New-SPSubscriptionSettingsServiceApplication -ApplicationPool "Default SharePoint Services App Pool" -Name "Subscriptions Settings Service" -DatabaseName "Subscriptions_Settings_Service_DB"</span></li>
<li>Next type (and press enter):<br /><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">New-SPSubscriptionSettingsServiceApplicationProxy -ServiceApplication $svcapp</span></li>
<li>Then Type (and press enter):<br /><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">Get-SPServiceInstance | Where-Object {$_.TypeName -eq "Microsoft SharePoint Foundation Subscription Settings Service"} | Start-SPServiceInstance</span></li>
<li>After you run the above commands, you can verify everything is set up by confirming the Database was created (in SQL Management Studio) and verify the service is set up and started in Central Admin</li>
</ol>
<li style="font-weight: normal;">Next you need to configure DNS, this will set up your environment to be more (secure) like a production environment instead of using Subdomains off your current domain for your apps (which has the potential for CSS attacks)</li>
<ol>
<li style="font-weight: normal;">Open DNS Manager and create a new, Primary forward lookup zone, with all the defaults</li>
<li style="font-weight: normal;">Give the zone name wingtipapps.com (or whatever name you want to use if you've strayed from the CP guide)</li>
<li style="font-weight: normal;">Click next through the remaining screens, accepting the defaults, then click finish.</li>
<li style="font-weight: normal;">Create a new CNAME by right clicking the domain you just created (wingtipapps.com) </li>
<ol style="font-weight: normal;">
<li>Put * for the Alias name</li>
<li>Put servername.wingtip.com. for your FQDN for target host</li>
</ol>
</ol>
<li>Finally you can create the App Management Service in CA</li>
<ol>
<li>Go to CA > Manage Service Applications</li>
<li>Click New on the Ribbon and choose "App Management Service" </li>
<ol>
<li>Give it the name "App Management Service"</li>
<li>Change the database name to App_Management_DB</li>
<li>Use an existing application pool and make sure your default Service App pool is selected</li>
<li>accept all other defaults and click OK at the bottom</li>
<li>If everything goes right you should see your App Management Service running in CA</li>
<li>The Service App will indicate it's started, but the Service actually isn't running until you go to "System Settings" > Manage Services On Server and click the start button on the Application Management Service line</li>
</ol>
</ol>
</ol>
<li>Next, let's configure BDC in CA</li>
<ol>
<li>Go to CA > Manage Service Applications</li>
<li>Click New on the Ribbon and choose the BDC service</li>
<ol>
<li>Name it BDC </li>
<li>Remove the GUID from the end of the DB name</li>
<li>Use the Existing Service App Pool</li>
<li>Then click OK at the bottom</li>
<li>Wait for the spinner to finish and you should see your BDC app in the Service Applications list</li>
<li>The Service App will indicate it's started, but the Service actually isn't running until you go to "System Settings" > Manage Services On Server and click the start button on the BDC Service line</li>
</ol>
</ol>
<li>Now for Excel Services</li>
<ol>
<li>Go to CA > Manage Service Applications</li>
<li>Click New on the Ribbon and choose the Excel Services Application</li>
<ol>
<li>Name it Excel Services </li>
<li>Use the Existing Service App Pool</li>
<li>Then click OK at the bottom</li>
<li>Wait for the spinner to finish and you should see your Excel Services app in the Service Applications list</li>
<li>The Service App will indicate it's started, but the Service actually isn't running until you go to "System Settings" > Manage Services On Server and click the start button on the Excel Calculation Services line</li>
</ol>
</ol>
<li>Next is Managed Metadata</li>
<ol>
<li>Go to CA > Manage Service Applications</li>
<li>Click New on the Ribbon and choose the Managed Metadata service</li>
<ol>
<li>Name it Managed Metadata Service </li>
<li>Name the DB "Managed_Metadata_DB"</li>
<li>Use the Existing Service App Pool</li>
<li>Then click OK at the bottom</li>
<li>Wait for the spinner to finish and you should see your Managed Metadata Service app in the Service Applications list</li>
<li>The Service App will indicate it's started, but the Service actually isn't running until you go to "System Settings" > Manage Services On Server and click the start button on the Managed Metadata Web Service line</li>
</ol>
<li>Now set your Managed Metadata Service to be the default storage location</li>
<ol>
<li>Go back to CA > Manage Service Applications</li>
<li>Select the <u>Managed Metadata Service Connection</u> line (not the link itself or you'll jump to the wrong screen). If you've done this right the line should highlight in light blue</li>
<li>Click the Properties button on the ribbon</li>
<li>Check the checkbox for "This service application is the default storage location for column specific term sets"</li>
<li>Click OK</li>
</ol>
</ol>
<li>Next is Secure Store</li>
<ol>
<li>Go to CA > Manage Service Applications</li>
<li>Click New on the Ribbon and choose the Secure Store service</li>
<ol>
<li>Name it Secure Store Service </li>
<li>Remove the GUID from the end of the DB name</li>
<li>Use the Existing Service App Pool</li>
<li>Then click OK at the bottom</li>
<li>Wait for the spinner to finish and you should see your Secure Store app in the Service Applications list</li>
<li>The Service App will indicate it's started, but the Service actually isn't running until you go to "System Settings" > Manage Services On Server and click the start button on the Secure Store Service line.</li>
</ol>
<li>Finally, generate a key</li>
<ol>
<li>Under CA > Manage Service Applications click the link for the Secure Store Application (the top one)</li>
<li>On the ribbon, click "Generate New Key"</li>
<li>type a good password twice. (I used P@ssword1)</li>
</ol>
</ol>
<li>Configure Visio</li>
<ol>
<li>Go to CA > Manage Service Applications</li>
<li>Click New on the Ribbon and choose the Visio Graphics service</li>
<ol>
<li>Name it Visio Graphics Service</li>
<li>Use the Existing Service App Pool</li>
<li>Then click OK at the bottom</li>
<li>Wait for the spinner to finish and you should see your Viso Graphics Service app in the Service Applications list</li>
<li>The Service App will indicate it's started, but the Service actually isn't running until you go to "System Settings" > Manage Services On Server and click the start button on the Secure Store Service line.</li>
</ol>
</ol>
<li>Configure Word Automation</li>
<ol>
<li>Go to CA > Manage Service Applications</li>
<li>Click New on the Ribbon and choose the Word Automation service</li>
<ol>
<li>Name it Word Automation Service</li>
<li>Use the Existing Service App Pool</li>
<li>Check the checkbox to Add this service applcation's proxy to the farm's default proxy list.</li>
<li>Then click OK at the bottom</li>
<li>The next screen will ask you for a database name, enter Word_Automation_DB</li>
<li>Wait for the spinner to finish and you should see your Viso Graphics Service app in the Service Applications list</li>
<li>The Service App will indicate it's started, but the Service actually isn't running until you go to "System Settings" > Manage Services On Server and click the start button on the Secure Store Service line.</li>
</ol>
</ol>
<li>Configure PowerPoint Conversion - I couldn't find any info in either book on this service so here's guidance based on info from technet: </li>
<ol>
<li>Open a SharePoint Powershell window console as adminsitrator and run the following commands (press enter after each line)</li>
<ol>
<li><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">$pool = Get-SPServiceApplicationPool | where {$_.Name -eq "Default SharePoint Service App Pool"}</span></li>
<li><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">$ppt = New-SPPowerPointConversionServiceApplication "PowerPoint Conversion Service" -ApplicationPool $pool</span></li>
<li><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">New-SPPowerPointConversionServiceApplicationProxy "PowerPoint Conversion Service Proxy" -ServiceApplication $ppt -AddToDefaultGroup</span></li>
<li><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">Start-SPServiceInstance | where($_.TypeName -eq "PowerPoint Conversion Service"} </span><span style="font-family: inherit;">[note: when I ran this command I got prompted for the Identity parameter for the PowerPoint Conversion Service Instance (which was annoying). You can get the Id by running</span><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> Get-SPServiceInstance | where {$_.TypeName -eq "PowerPoint Conversion Service"}</span></li>
</ol>
</ol>
<li>Configure Work Management (as stated earlie we have to provision 3 service apps to get this working)</li>
<ol>
<li>Configure Search Service. You'll probably want to paste this into the ISE because there's quite a few lines:<br /><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br />Add-PSSnapin "Microsoft.SharePoint.Powershell" -ErrorAction SilentlyContinue<br /><br />#ensure this matches the name of your SP Service App Pool</span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br />$saAppPoolName = "Default SharePoint Service App Pool"<br /><br />#you should replace the value for the Server Name below with your server name<br /><br />$searchServerName ="SP2013DEVR201"<br />$serviceAppName = "Search Service Application"</span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">$searchDBName = "Search_Service_DB"</span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">$saAppPool = Get-SPServiceApplicationPool $saAppPoolName</span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br />#start Search Host Controller Service and Search Query and Site Settings Service (you should see these in the Manage Services on Server Page</span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br />Start-SPEnterpriseSearchServiceInstance $searchServerName</span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br />Start-SPEnterpriseSearchQueryAndSiteSettingsServiceInstance $searchServerName</span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br />#create search application and proxy (you should see these on the Manage Service Applications Page, NOTE: the first line takes quite a while to run)</span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br />$searchServiceApp = New-SPEnterpriseSearchServiceApplication -Name $serviceAppName -ApplicationPool $saAppPoolName -DatabaseName $searchDBName</span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br />$searchProxy = New-SPEnterpriseSearchServiceApplicationProxy -Name "$serviceAppName Proxy" -SearchApplication $searchServiceApp</span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br />#now clone the topology, add components</span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br />$clone = $searchServiceApp.ActiveTopology.Clone()</span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br />$searchServiceInstance = Get-SPEnterpriseSearchServiceInstance</span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br />New-SPEnterpriseSearchAdminComponent -SearchTopology $clone -SearchServiceInstance $searchServiceInstance</span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br />New-SPEnterpriseSearchContentProcessingComponent -SearchTopology $clone -SearchServiceInstance $searchServiceInstance</span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br />New-SPEnterpriseSearchAnalyticsProcessingComponent -SearchTopology $clone -SearchServiceInstance $searchServiceInstance</span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br />New-SPEnterpriseSearchCrawlComponent -SearchTopology $clone -SearchServiceInstance $searchServiceInstance</span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br />New-SPEnterpriseSearchIndexComponent -SearchTopology $clone -SearchServiceInstance $searchServiceInstance</span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br />New-SPEnterpriseSearchQueryProcessingComponent -SearchTopology $clone -SearchServiceInstance $searchServiceInstance</span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br />#finally, activate the topology, NOTE this also takes quite a while to run</span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br />$clone.Activate()</span></li>
<li>Configure User Profile Service (from CP guidance and in Chapter 14 of <a href="http://www.amazon.com/gp/product/1118495810/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1118495810&linkCode=as2&tag=sharep03-20&linkId=R7ZYFPVXBZRBRERV" target="_blank">Professional SharePoint 2013 Administration</a>)</li>
<ol>
<li>Configure the MySite web application</li>
<ol>
<li><b>Following the CP guidance, you can run their "Script04_CreateWebApplications.ps1", but you have to edit the script and replace any reference to WINGTIP\Administrator to match the Admin account you're logged in as (you can't choose Administrator as your login in Azure since that's reserved)</b> here. Anyway, it's a good idea to read through the script. This will create the MySite web application (along with the web app for the HNSC, Intranet, and Team sites)</li>
</ol>
<li>Next Configure the User Profile Service using the Script06_CreateUserProfileServiceApplication.ps1</li>
<ol>
<li>Read through the Script06_CreateUserProfileServiceApplication.ps1 and update the Administrator account (since you're not logged into your Azure VM as an account named "Administrator".</li>
<li>Read through the CreateUserProfileServiceApplicationScript.ps1 and ensure the server name/domain/accounts accurately reflect your environment.</li>
<li>Run the Script06_CreateUserProfileServiceApplication.ps1 and verify that it completes without error</li>
<li>Next go to CA > Manage Service Applications > User Profile Service Application</li>
<li>Create a new Synchronization Connection with the following values;</li>
<ol>
<li>Connection Name: [Domain] Users (wingtip if you use CP guidance)</li>
<li>Type: Active Directory</li>
<li>ForestName: yourdomain.com (e.g. wingtip.com)</li>
<li>Specify A domain controller</li>
<li>Domain Controller Name: Your VM machine name</li>
<li>Authentication Provider Type: Windows Authentication</li>
<li>Account Name: [DOMAIN]\SP_UPS</li>
<li>Password: Password1 (if you've used the CP Guidance)</li>
<li>Click Populate containers, if you've configured the above correctly it should load your domain node</li>
<li>Choose the Users group the CP script set up.</li>
<li>Click OK</li>
</ol>
<li>GO back to the User Profile Service Application management page and start a full import. 15 more profiles should get imported</li>
</ol>
</ol>
</ol>
<li>Configure Workflow</li>
<ol>
<li>Read through the Script05_CreateWorkflowFarm.ps1 script and ensure you update the reference from WINGTIP\Administrator to the correct Admin account</li>
<li>Read through the CreateWorkflowFarmScript.ps1 and ensure you update the Administrator account as above.</li>
<li>Run the Script05_CreateWorkflowFarm.ps1 script.</li>
<li>NOTE: If you decide to run the Script05 in the ISE, you'll get a security prompt when PS attempts to open another console window to run the CreateWorkflowFarmScript.ps1 so make sure you allow it when prompted.</li>
</ol>
<li>Finally, Remove the SP_Farm account from the local admin group.</li>
<li>Configure Search:</li>
<ol>
<li>We've already created the search application when we created the work management application but there's a few changes to make</li>
<ol>
<li>Go to CA>Manage Service Applications > Search Service</li>
<li>Under content access account, change it to "SP_Crawler" rather than SP_Services or SP_Farm</li>
<li>Now give SP_Crawler access to the user profile service application</li>
<ol>
<li>go to CA > Manage Services on Server</li>
<li>Select the user profile service application (but don't click the link on the name) so that you can select Administrators from the ribbon</li>
<li>in the administrators dialog that pops up add SP_Crawler, then give it "Retrieve People Data for Search Crawlers" rights.</li>
</ol>
<li>You'll also need to go back to the Search Administration screen and add sps3://my.wingtip.com (or whatever you called it) as a content source and add a crawl rule to add the sps3://my.wingtip.com.</li>
<ol>
</ol>
</ol>
<li>Now start a full crawl on the Local SharePoint sites content source (in the Search Service Application management screen)</li>
<li>You should now be able to do the CP Search Tests described in their documentation (People Search for John, "Everything" search for Local_Admin - or whatever your admin User name is)</li>
</ol>
</ol>
</ol>
</ol>
<div>
<br /></div>
</div>
</li>
</ol>
</ol>
</ol>
<div>
At this point you should be good to continue on P73 of the CP guidance and work your way through the rest of the config. If you follow their directions (ensure you modify any domain/users and server names if you've strayed).</div>
<div>
<br /></div>
<div>
In summary, the CP Guidance is very good for beginners, but I encourage you to gain a full understanding of what their scripts do, and avoid the configuration wizard entirely as it's better that you understand all aspects of the setup rather than rely on Wizard Magic.</div>
<div>
<br /></div>
<div>
In the near future I'll try to get this guidance into an AutoSPInstaller script to really make things interesting.</div>
<ol><ol><ol>
<li><div>
<ol><ol><ol><ol>
</ol>
</ol>
</ol>
</ol>
<div style="font-weight: normal;">
<b>Summary of resources for this post:</b></div>
<div style="font-weight: normal;">
<ol>
<li>Critical Path Training VM Guide (this guide uses version 3.0): available in the (free sign up) members section of <a href="http://www.criticalpath.com/">www.criticalpath.com</a> </li>
<li><a href="http://www.amazon.com/gp/product/1118495810/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1118495810&linkCode=as2&tag=sharep03-20&linkId=R7ZYFPVXBZRBRERV" target="_blank">Professional SharePoint 2013 Administration Book</a></li>
<li><a href="http://blogs.sharepoint911.com/blogs/shane/Lists/Posts/Post.aspx?ID=8" target="_blank">Shane Young's SQL Server Install guide for SP2013</a> </li>
<ol>
<li><a href="http://msdn.microsoft.com/en-us/library/ms181007(v=SQL.105).aspx" target="_blank">Understanding Max Degrees of Parallelism</a></li>
</ol>
</ol>
</div>
</div>
</li>
</ol>
</ol>
</ol>
Paulhttp://www.blogger.com/profile/05424579499113928113noreply@blogger.com0tag:blogger.com,1999:blog-5634441641513879577.post-30761158538890565542014-07-10T13:56:00.000-07:002014-07-19T09:34:39.744-07:00SharePoint Solution DownloaderSpecial thanks to Djamel Chagour and his response to my MSDN thread (which linked to <a href="http://spbyexamples.blogspot.com/2009/07/batch-solution-deployment-between-farms.html">this blog post</a>) to solve my issue of grabbing solutions from the Solution store so I could drop them on another server.
<br />
<br />
His post is more complex and deals with generating the stsadm commands for a batch deployment. Mine is the dumbed down version that just pulls the files so I can readd them as I need them.
<br />
<br />
Here's the code:
<br />
<br />
<br />
<!-- code formatted by http://manoli.net/csharpformat/ -->
<br />
<pre class="csharpcode"><span class="kwrd">using</span> System;
<span class="kwrd">using</span> System.Collections.Generic;
<span class="kwrd">using</span> System.Linq;
<span class="kwrd">using</span> System.Text;
<span class="kwrd">using</span> System.IO;
<span class="kwrd">using</span> Microsoft.SharePoint;
<span class="kwrd">using</span> Microsoft.SharePoint.Administration;
<span class="kwrd">using</span> System.Xml;
<span class="kwrd">using</span> System.Web;
<span class="kwrd">namespace</span> Mirant.SharePoint.Administration.WSPDownloader
{
<span class="kwrd">class</span> Program
{
<span class="kwrd">static</span> <span class="kwrd">void</span> Main(<span class="kwrd">string</span>[] args)
{
<span class="kwrd">bool</span> hasErrors = <span class="kwrd">false</span>;
<span class="kwrd">if</span> (args.Length != 1)
{
Console.WriteLine(<span class="str">"Usage: Company.SharePoint.Administration.WSPDownloader directory\r\n\tdirectory: full path on the local file system that you want the solutions downloaded to"</span>);
hasErrors = <span class="kwrd">true</span>;
}
<span class="kwrd">if</span> (!hasErrors)
{
<span class="kwrd">string</span> path = args[0];
path = path.Replace(<span class="str">"\""</span>, <span class="str">""</span>);
<span class="kwrd">if</span> (!path.EndsWith(<span class="str">"\\"))
path += "</span>\\";
SPSolutionCollection solutions = SPFarm.Local.Solutions;
<span class="kwrd">foreach</span> (SPSolution solution <span class="kwrd">in</span> solutions)
{
SPPersistedFile wspFile = solution.SolutionFile;
wspFile.SaveAs(path + solution.Name);
}
}
}
}
}</pre>
Paulhttp://www.blogger.com/profile/05424579499113928113noreply@blogger.com0tag:blogger.com,1999:blog-5634441641513879577.post-64405352831834628772014-07-10T13:26:00.002-07:002014-07-10T13:58:06.939-07:00Movin on Up: Converting a VDI to a VHD to move from VirtualBox to AzureMonths (years?) behind the rest of the world, I've finally decided it's time to get my VMs up to Azure (no more SSD swapping between PC and laptop despite having a easily mountable caddy in my work laptop and this <a href="http://www.amazon.com/gp/product/B001CYZC38/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=B001CYZC38&linkCode=as2&tag=sharep03-20&linkId=IX4VV2NBE7FWK3EQ" target="_blank">sweet caddy in my PC</a>. <br />
<br />
As a loyal VirtualBox user I opted for VDI rather than VHD, but now I must convert. So here's what I did:<br />
<br />
<ol>
<li>Uninstall VBox Guest Additions from the VM</li>
<li>Shut the VM down (don't save the state).</li>
<li>Remove the VDI from the Virtual Media Manager in Virtual box before running the command below</li>
<li>Run the following command using Run As Administrator by right-clicking on the command prompt (from the VBox Install directory unless you've set the PATH variable): VBoxManage clonehd e:\SP2013DEV.vdi c:\SP2013DEVaz.vhd --format VHD<br /><br />In the above command the first file is the source VDI the second is the destination VHD.</li>
<li>Wait for the magic to happen it should take a while since VMs with SP on them are pretty big. Going from one drive to another should help a bit.</li>
<li>Upload to Azure and config a new VM to use that VHD.</li>
<li>Profit</li>
</ol>
<div>
I ran into a hiccup in that it appears my vbox installation got messed up during an upgrade and kept telling me that VBoxManage was not a vaild win32 application because it was a zero byte file. Reinstalling VBox did the trick.</div>
<div>
<br /></div>
<div>
I may go to just configuring straight in Azure from now on. I do like the option of building locally then uploading, but I will probably just start with the VHD format from now on since conversion is really just an extra step if you plan on going to Azure.</div>
Paulhttp://www.blogger.com/profile/05424579499113928113noreply@blogger.com0tag:blogger.com,1999:blog-5634441641513879577.post-83582462719248756582013-04-27T09:42:00.000-07:002013-04-27T09:43:25.503-07:00Deleted Site Collection continues to show up in Central AdminIn working through my <a href="http://sharepointers.blogspot.com/2013/04/getting-started-with-host-named-site.html">last post</a> I managed to leave a remnant in Central Admin of a removed Host Named Site Collection that was stored in the default HNSC Content database. After many attempts to repair in a more acceptable way, (DB Repairs, removing/adding content db, etc) I finally realized that the issue wasn't in my HNSC content db, but rather a leftover reference in the<b> SharePoint_Config DB</b>. Taking a page from the book-of-things-you-should-never-do-in-SharePoint, I found the reference in the <b>SiteMap </b>table and had to manually delete that row. <u><b>I <span style="color: red;">backed up the database first</span> in anticipation of impending doom</b></u>, but it seems to have done the trick.<br />
<br />
I'm going to poke around the internet a little more, hoping there's a better way to clean this up or even some timer job or other process that takes care of this in the future, but if you know of the better way, please post it.<br />
<br />
<br />Paulhttp://www.blogger.com/profile/05424579499113928113noreply@blogger.com0tag:blogger.com,1999:blog-5634441641513879577.post-11455591613505964832013-04-27T09:00:00.001-07:002013-04-27T09:44:01.877-07:00Getting Started With Host Named Site Collections - PowerShell ScriptWell, it's been a while, but I'm finally getting around to really digging deep into SP2013. As I go through this I figured I'd start putting together a few helper PowerShell Scripts:<br />
<br />
<br />
Once you've got a SP2013 developer machine created you may want to stand up additional Host Named Site Collections (If you haven't created one yet, use the Critical Path Training guide at http://www.criticalpathtraining.com in the Members section). I've also included the ability to stand up a new ContentDB for your site collection.<br />
<br />
Here's a relatively simple Powershell script to help you with this:<br />
<br />
<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">$snapin = Get-PSSnapin | Where-Object { $_.Name -eq "Microsoft.SharePoint.Powershell" }</span><br />
<span style="font-family: Courier New, Courier, monospace;">if($snapin -eq $null)</span><br />
<span style="font-family: Courier New, Courier, monospace;">{</span><br />
<span style="font-family: Courier New, Courier, monospace;"> Write-Host "...loading Microsoft.SharePoint.PowerShell snapin" -ForegroundColor Gray</span><br />
<span style="font-family: Courier New, Courier, monospace;"> Add-PSSnapin Microsoft.SharePoint.PowerShell</span><br />
<span style="font-family: Courier New, Courier, monospace;">}</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">function CreateHNSC($name, $url, $template, $contentdatabasename)</span><br />
<span style="font-family: Courier New, Courier, monospace;">{</span><br />
<span style="font-family: Courier New, Courier, monospace;"> $defaultWebApp = Get-SPWebApplication |</span><br />
<span style="font-family: Courier New, Courier, monospace;"> Where-Object { $_.IisSettings["Default"].ServerBindings[0].Port -eq 80 -and $_.IisSettings["Default"].ServerBindings[0].HostHeader -eq "" }</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;"> if($defaultWebApp){</span><br />
<span style="font-family: Courier New, Courier, monospace;"> $ownerAlias = [Environment]::UserDomainName + "\" + [Environment]::UserName</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;"> if($contentdatabasename)</span><br />
<span style="font-family: Courier New, Courier, monospace;"> {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> Write-Host "Creating new content database '$contentdatabasename'"</span><br />
<span style="font-family: Courier New, Courier, monospace;"> New-SPContentDatabase -Name $contentdatabasename -WebApplication $defaultWebApp</span><br />
<span style="font-family: Courier New, Courier, monospace;"> </span><br />
<span style="font-family: Courier New, Courier, monospace;"> Write-Host "Creating new Host Named Site Collection '$name' at $url (in '$contentdatabasename' content database)"</span><br />
<span style="font-family: Courier New, Courier, monospace;"> New-SPSite -Name $name -Url $url -HostHeaderWebApplication $defaultWebApp -Template $template -OwnerAlias $ownerAlias -ContentDatabase $contentdatabasename</span><br />
<span style="font-family: Courier New, Courier, monospace;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace;"> else</span><br />
<span style="font-family: Courier New, Courier, monospace;"> {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> Write-Host "Creating new Host Named Site Collection '$name' at $url (in default HNSC content database)"</span><br />
<span style="font-family: Courier New, Courier, monospace;"> New-SPSite -Name $name -Url $url -HostHeaderWebApplication $defaultWebApp -Template $template -OwnerAlias $ownerAlias</span><br />
<span style="font-family: Courier New, Courier, monospace;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace;"> else{</span><br />
<span style="font-family: Courier New, Courier, monospace;"> Write-Host "default SP2013 web application was not found" -ForegroundColor Red</span><br />
<span style="font-family: Courier New, Courier, monospace;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace;">}</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">#call the function for each host named site colletion you want to create</span><br />
<span style="font-family: Courier New, Courier, monospace;">#with new content db</span><br />
<span style="font-family: Courier New, Courier, monospace;">CreateHNSC -name "Solutions Site" -url "http://solutions.mydomain.com" -template "DEV#0" -contentdatabasename "WSS_Content_Solutions"</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">#to default content db</span><br />
<span style="font-family: Courier New, Courier, monospace;">#CreateHNSC -name "Solutions Site 2" -url "http://solutions2.mydomain.com" -template "DEV#0"</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">One thing to remember (and might be worth handling in this script in the future) is that if you're using this to set up HNSCs on a dev machine, you'll need to add the additional hosts to your hosts file or Visual Studio won't recognize your new host. This appears to be a known bug.</span><br />
<div>
<br /></div>
Paulhttp://www.blogger.com/profile/05424579499113928113noreply@blogger.com0tag:blogger.com,1999:blog-5634441641513879577.post-89437359863918815552012-01-04T13:58:00.000-08:002012-01-04T14:33:24.612-08:00Using JQuery to Tweak Editform.aspxFor smaller changes to your Editform.aspx you may want to avoid doing a solution deployment that contains a custom content type feature with a custom EditForm.aspx. This is a quick workaround. It's pretty much the same as we used to to in MOSS with only minor changes to the way you get to the form.<br />
<br />
I did this in IE, but it's probably similar in other browsers:<br />
<br />
<br />
<ol><li>Place an html document containing some JavaScript/Jquery into a document library on your list's site. (Try just putting this for initial testing: <script type="text/javascript">alert('hello world');</script>)</li>
<li>Navigate to the list whose editform.aspx you want to change</li>
<li>Right click on any item's link to it's display form and choose 'open in new tab'</li>
<li>Go to the newly opened tab and click the 'Edit Item' button to open the item in the editform.aspx</li>
<li>append &ToolPageView=2 to the url</li>
<li>Add a Content Editor Web Part and point it to your document from step 1.</li>
</ol><div>This shouldn't be a replacement for all customized EditForm.aspx's by any means, but it's still a useful trick for quick fixes that don't justify custom development.</div>Paulhttp://www.blogger.com/profile/05424579499113928113noreply@blogger.com0tag:blogger.com,1999:blog-5634441641513879577.post-28268931663349508552011-10-12T09:38:00.000-07:002011-10-12T09:40:29.209-07:00Opening an Infopath form library template from Infopath in a linkI've found a lot of bad info on how to do this and it's not well documented so hopefully this helps someone:<br />
<br />
first create a JavaScript function so that your links aren't super long:<br />
<br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 0pt;"><script type="text/javascript"><o:p></o:p></div> function OpenForm(absSiteUrl, siteRelFormUrl, siteRelSaveUrl)<o:p></o:p><br />
{<o:p></o:p><br />
var formUrl = absSiteUrl + siteRelFormUrl;<o:p></o:p><br />
var saveUrl = absSiteUrl + siteRelSaveUrl;<o:p></o:p><br />
var formSvcUrl = absSiteUrl + "_layouts/FormServer.aspx?XsnLocation=" + formUrl;<o:p></o:p><br />
CoreInvoke('createNewDocumentWithRedirect2',event, formUrl, saveUrl, 'SharePoint.OpenXmlDocuments.2', true, formSvcUrl, false, 0);<o:p></o:p><br />
}<o:p></o:p><br />
</script><o:p></o:p><br />
<br />
then create a link like so:<br />
<br />
<span style="font-family: "Times New Roman","serif"; font-size: 11pt; mso-ansi-language: EN-US; mso-bidi-language: AR-SA; mso-fareast-font-family: Calibri; mso-fareast-language: EN-US; mso-fareast-theme-font: minor-latin;"><a href="javascript:OpenForm('[AbsoluteSiteUrl]','[SiteRelativeFormUrl]','[SiteRelativeSaveLocationUrl]')">open form</a></span><br />
<br />
here are examples for the vars<br />
[AbsoluteSiteUrl] = <a href="http://mysp2010server/siteA/">http://mysp2010server/siteA/</a><br />
[SiteRelativeFormUrl] = myformlibrary/Forms/template.xsn<br />
[SiteRelativeSaveLocationUrl] = myformlibraryPaulhttp://www.blogger.com/profile/05424579499113928113noreply@blogger.com0tag:blogger.com,1999:blog-5634441641513879577.post-81492405103727696972011-10-11T07:31:00.000-07:002011-10-11T07:50:41.616-07:00People Search from MySite returns 404If you have MySites and a Search Center running in your farm, you may have overlooked a not-so-obvious configuration setting. When setting up MySites for a User Profile service application, your Search Center URL must point to the "Pages" folder where the Search Center publishing pages are located instead of the Search Center web URL. Otherwise, a People Search from a MySite will forward the request to to<br /><span style="font-family: courier new;"><br /> http://[searchcenter]/PeopleResults.aspx?k=searchquery</span><br /><br />(which doesn't exist) instead of<br /><br /><span style="font-family: courier new;"> http://[searchcenter]/PeopleResults.aspx?k=searchquery</span><br /><br />which is where the <span style="font-family: courier new;">PeopleResults.aspx</span> page is actually located.<br /><br /><br />TLDR: Use <span style="font-family: courier new;">http://[searchcenter]<span style="font-weight: bold;">/Pages/</span></span> for your Search Center url in UPA MySite Settings.Byronhttp://www.blogger.com/profile/15543587546770804717noreply@blogger.com0tag:blogger.com,1999:blog-5634441641513879577.post-19709031067445020172011-09-08T14:08:00.000-07:002011-09-09T09:26:54.246-07:00Including a JS file for a custom ribbon control CommandUIHandler without using a ScriptLink CustomAction or Custom Page ComponentsI've been struggling lately with the proposed solutions for including the javascript for CommandUIHandler's CommandAction and EnabledScript attributes. Thus far I have only seen the following examples:<br />
<br />
<ol><li>JavaScript directly into the attributes (messy), </li>
<li>Including a ScriptLink command action (bad because then the script file is included in every page where the feature is activated causing bloated pages)</li>
<li>Creating a page component (overcomplicated)</li>
</ol>Instead of all this, I created a pattern which loads the js file on the fly with javascript and keeps your ribbon development more compact (note I have JQuery loaded in the master page, if you don't have this then you'll have to either load jquery dynamically or reference the elements without JQuery):<br />
<br />
<commanduihandler <br="" command="MyCommand"> </br=""><br />
<br="" command="MyCommand"> CommandAction="javascript:<br />
$.getScript('/_layouts/myProject/myScriptfile.js', function(){ commandActionMethodInJSFile(); });"<br />
EnabledScript="javascript:<br />
function enabledController()<br />
{<br />
if(typeof checkIsEnabledMethodFromJSFile == 'undefined')<br />
{<br />
$.getScript('/_layouts/myProject/myScriptfile.js', function(){ RefreshCommandUI(); });<br />
return false;<br />
}<br />
else return checkIsEnabledMethodFromJSFile();<br />
}<br />
enabledController();<br />
"<br />
<br />
<br />
/><br />
<br />
The CommandAction is simple, just load the script file with the jQuery getScript() method and call your ribbon action in the callback.</br=""><br />
<br />
<br="" command="MyCommand">The real trick was handling the Asynchronous load in the EnabledScript since it will just finish before the callback occurs. What this does is check to see if the method in your JS file has been loaded, if not it calls the jQuery getScript to load the file and then keeps the control disabled, then once the callback happens it calls 'RefreshCommandUI' to notify the ribbon that something has happened and it needs to evaluate the Enabled condition again. This time, the method does exist because the script is loaded and thus you can call your enabled check method in your script file.</br=""><br />
<br />
Giving credit where it's due, Andrew Connell's post helped me find the missing piece to my solution : <a href="http://www.andrewconnell.com/blog/archive/2010/10/14.aspx">http://www.andrewconnell.com/blog/archive/2010/10/14.aspx</a><br />
<br="" command="MyCommand">Hopefully this will help you keep your Ribbon development more simplified.</br="">Paulhttp://www.blogger.com/profile/05424579499113928113noreply@blogger.com1tag:blogger.com,1999:blog-5634441641513879577.post-84389611023717413532011-08-10T14:56:00.000-07:002011-08-10T14:56:06.887-07:00Quickly determine which PID corresponds to which App Pool's w3wp.exeThis is a command that will quickly let you know which w3wp.exe you should be debugging on Server 2008 (IIS7, since the App Pool isn't listed in Visual Studio's 'attach to process' dialog).<br />
<br />
go to \Windows\System32\inetsrv and run "appcmd list wp" and you'll get a list that associates App Pool and PIDPaulhttp://www.blogger.com/profile/05424579499113928113noreply@blogger.com0tag:blogger.com,1999:blog-5634441641513879577.post-56077088494004953342011-04-27T19:31:00.000-07:002011-04-27T19:32:11.385-07:00PowerShell code for looking up document propertiesIf you want to use the SPWeb.Files.Add() method that allows you to pass in a HashTable of metadata for the document, you will need to use the internal name of the metadata field, not the display name. Here's a PowerShell script to get that for you quickly:<br />
<br />
<br />
$web = Get-SPWeb <a href="http://intranet.sharepointdev.com/">http://intranet.sharepointdev.com</a><br />
$list = $web.Lists["Shared Documents"]<br />
foreach($item in $list.Items)<br />
{<br />
$file = $item.File<br />
#output all the SPFile property names<br />
foreach($key in $file.Properties.Keys)<br />
{ <br />
write-host("File Key: " + $key)<br />
}<br />
<br />
#output the associated item's fields<br />
foreach($field in $item.Fields)<br />
{<br />
write-host("Item Field: " + $field.InternalName)<br />
}<br />
break;<br />
}Paulhttp://www.blogger.com/profile/05424579499113928113noreply@blogger.com0tag:blogger.com,1999:blog-5634441641513879577.post-63591288277430705412011-03-10T20:57:00.000-08:002011-03-10T20:57:38.914-08:00Understanding Sandboxed SolutionsThere are several components/processes that are involved in the execution of sandboxed solutions. For a developer, it's critical to understand how coding/debugging various types of solutions changes based on the type of solution. Here's how the execution goes in a nutshell:<div><br />
</div><div>When the sandboxed code is called, the Execution Manager (running in the w3wp.exe) makes a call to an application server running the User Code Service (SPUCHostService.exe). The User Code Service then tells the Worker Service (SPUCWorkerProcess.exe) to load the sandbox code. The code is then verified to ensure only calls to the subset of the API allowed by the Sandbox API are called. The worker process then executes the code against the Worker Proxy (SPUCWorkerProcessProxy.exe) which has full access to the SharePoint API (but the sandboxed code has already been disallowed from using the non-subset portion of the API by the Worker Service).</div><div><br />
</div><div>When debugging sandboxed solutions, you'll need to attach to the SPUCWorkerProcess.exe to step through your code.</div><div><br />
</div><div>Finally, the exe's for all the .exe's metioned above (except w3wp.exe) can be found in your 14\UserCode directory.</div>Paulhttp://www.blogger.com/profile/05424579499113928113noreply@blogger.com0tag:blogger.com,1999:blog-5634441641513879577.post-6165655376281888172011-01-03T10:49:00.000-08:002011-01-03T11:19:21.215-08:00Thoughts on SharePoint 2010 Search RefinementI've been spending a lot of time lately working with SharePoint 2010's "Refinement Panel" web part.<br /><br />This capability was available only as a third-party add-in or <a href="http://facetedsearch.codeplex.com/">Codeplex solution </a>back in the MOSS days, but I was very excited to learn that it had been incorporated natively in 2010.<br /><br />It's frustrating, however, to have to constantly explain to customers that Refinement goes only 500 results deep unless you have FAST, which requires Enterprise CALs. The standard search provides a Refinement Panel that defaults to an Accuracy Index of 50 and goes to a maximum of 500. This means that the Refinement capability will only work for the first 50-500 results returned.<br /><br /><br /><img style="TEXT-ALIGN: center; MARGIN: 0px auto 10px; WIDTH: 225px; DISPLAY: block; HEIGHT: 362px; CURSOR: hand" id="BLOGGER_PHOTO_ID_5558036753989309474" border="0" alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGtfs93ndaUwIXYL_rNklgC8djik9jVgWucXvhV9-dtFAbh5kC1iLeYmP1I3RxnwizWzkuYP_CEgmq6uUb1Hpd4CRK9iNlUeN8KYq9VOE0mMo3dVEmG8EyYKBLVRTH7jI-8uKmmX5ku48g/s400/Refinement-Panel.png" /><br />So if a company is stuck with Standard CALs and no FAST, how do they get around this limitation? Surely a mid to large size company will have many more than 500 list items, documents and other artifacts returned in a global search of all content sources, including SharePoint sites, File Shares, etc.<br /><br />So in our hypothetical mid to large size company scenario where a search for "widget" returns 5,000 results, how do we mitigate the problem I've outlined with the Refinement Panel? Well, there are a couple of ways:<br /><br /><ul><li>Create focused search scopes</li><li>Remove the Refinement Panel web part for global searches</li></ul><p>Fortunately, data from systems connected via Business Connectivity Services can't be used until you reach the Enterprise CAL level, either, so definitely use FAST for that and many other search improvements. </p><p>To conclude, don't fret if you're stuck with just the Standard CAL search experience. There are a few things you can do to make it a little better, especially with the Refinement Panel:</p><ul><li>if you do use the Refinement Panel, limit results by creating scopes</li><li>Change the default Accuracy Index from 50 to 500 (the maximum in Standard)</li><li><a href="http://sharepointbloggin.com/2010/10/25/add-an-item-count-to-the-sharepoint-2010-refinement-panel/">Enable Counts for your Refinement Panel</a></li><li>...but be sure to uncheck the "Use Default Configuration" box in the toolpart. :)</li></ul><p></p>Grant W. Earlhttp://www.blogger.com/profile/14571828655700749671noreply@blogger.com0tag:blogger.com,1999:blog-5634441641513879577.post-35064843920236108582010-09-23T07:55:00.000-07:002010-09-23T07:55:18.184-07:00Latest ASP.NET Vulnerability Fix For SharePointThe latest discovered ASP.Net vulnerability affects SharePoint 2007 & 2010. The SharePoint Team's blog has the instructions for the temporary fix here:<br />
<br />
<a href="http://blogs.msdn.com/b/sharepoint/archive/2010/09/21/security-advisory-2416728-vulnerability-in-asp-net-and-sharepoint.aspx">http://blogs.msdn.com/b/sharepoint/archive/2010/09/21/security-advisory-2416728-vulnerability-in-asp-net-and-sharepoint.aspx</a>Paulhttp://www.blogger.com/profile/05424579499113928113noreply@blogger.com0tag:blogger.com,1999:blog-5634441641513879577.post-67386042707220402702010-09-22T13:07:00.000-07:002010-09-22T13:07:56.712-07:00Turn on versioning on a site's Document Libraries.We had a lot of sites that needed to have versioning turned on, here's a simple console app I wrote to do this, you just pass the url of the web as an argument:<br />
<div><br />
</div><div><div>using System;</div><div>using System.Collections.Generic;</div><div>using System.Linq;</div><div>using System.Text;</div><div>using Microsoft.SharePoint;</div><div><br />
</div><div>namespace Mirant.Utilities.SiteVersioningActivator</div><div>{</div><div> class Program</div><div> {</div><div> static void Main(string[] args)</div><div> {</div><div> if (args.Length != 1)</div><div> throw new Exception("URL of the site is required as a parameter");</div><div><br />
</div><div><br />
</div><div> string webUrl = args[0];</div><div><br />
</div><div> using (SPSite site = new SPSite(webUrl))</div><div> {</div><div> using (SPWeb web = site.OpenWeb())</div><div> {</div><div><br />
</div><div> foreach (SPDocumentLibrary docLib in web.GetListsOfType(SPBaseType.DocumentLibrary))</div><div> {</div><div> docLib.EnableVersioning = true;</div><div> docLib.MajorVersionLimit = 5;</div><div> docLib.Update();</div><div> }</div><div> }</div><div> }</div><div> }</div><div> }</div><div>}</div></div><div><br />
</div>Paulhttp://www.blogger.com/profile/05424579499113928113noreply@blogger.com0