Mass Create Word Documents Using PowerShell

I’m my other post,  I outlined how to create a bunch of folders in a Document Library.  In this post, I’ll explain how I then populated those folders with Word documents.

To stage this, I created a Document Library called BaseLibrary.  In BaseLibrary I uploaded a single Word document.  After uploading the document, make note of the ID of the document in the Library.  *To get the ID of the document, modify your default View, and add the ID column, click save.*


if(-not(Get-PSSnapin | where { $_.Name -eq "Microsoft.SharePoint.PowerShell"}))
{
      Add-PSSnapin Microsoft.SharePoint.PowerShell;
}

$site = Get-SPweb "http://sharepointed.com/taco"

$spListFrom = $site.lists["BaseLibrary"]
$iFrom = $spListFrom.GetItemById("1")

$mList=$site.Lists["Shared Documents"]

foreach($f in $mlist.Folders)
 {

$fName=$f.Name

$range = 1..500
 $count = $range.Count
 for($i=0; $i -lt $count; $i++)
 {
 $nName = "$fName$i.docx"
 $nURL = $site.Url+''+$f.Url+"/"+$nName
 $iFrom.CopyTo($nURL)
 }
 }

$site.dispose()

What I’m doing here is referencing the document with the ID of 1, from BaseLibrary.

Loop through all the folders in Shared Documents, in each folder, I’m doing a loop to copy the document into the folder, and create a new name for the document on each loop.

$nName = “$fName$i.docx”

$fname is the name of the folder we are working with.

$i is the count of the loop we are on.  Joining the two variables will create a unique file name.

$range = 1..500

To create more or less documents in each folder, adjust this range.  This example will create 500 documents in each folder.

use PowerShell to create a bunch of folders

I’m going to explain this idea in two posts.  This post will outline creating a bunch of folders in a Document Library.  After the folders are created, I will then demonstrate how to put a bunch of Word documents in the newly created folders.

Why?

I was needing a way to stress test / performance test updating documents in SharePoint.


if(-not(Get-PSSnapin | where { $_.Name -eq "Microsoft.SharePoint.PowerShell"}))
{
      Add-PSSnapin Microsoft.SharePoint.PowerShell;
}

$site = Get-SPweb "http://sharepointed.com/taco/"
$mList = $site.Lists["Shared Documents"]

$range = 1..1000

$count = $range.Count
for($i=0; $i -lt $count; $i++)
 {
 $spFolder = $mList.AddItem("",[Microsoft.SharePoint.SPFileSystemObjectType]::Folder,$i)
 $spFolder.Update()
 }

$site.dispose()

$range can be adjusted to create less or more folders.  If you only wanted to create ten folders, change $range = 1..10

I’m using the incremented value of $i to name the folders. You can setup a another naming convention for the foldering.

In the next post, I will populate the folders with a Word document.

Use PowerShell to Loop Through Folders in a Library

Here is an example of using PowerShell to look through folders in a SharePoint Document Library.


if(-not(Get-PSSnapin | where { $_.Name -eq "Microsoft.SharePoint.PowerShell"}))
{
      Add-PSSnapin Microsoft.SharePoint.PowerShell;
}

$site = Get-SPweb "http://sharepointed.com/site/taco/"

$mList=$site.Lists["Shared Tacos"]

foreach($f in $mlist.Folders)
 {
 Write-Host $f.Name
 }

$site.dispose()

The item is currently locked for editing. Waiting for item to be checked in or for the lock to be released

Workflow error:

The item is currently locked for editing. Waiting for item to be checked in or for the lock to be released.

Working with SharePoint Designer 2010 and InfoPath, I created a workflow to perform an Action once a form was submitted or changed.

The error above was stopping the workflow from running any of the Steps / Actions.

The fix was to add a Wait for Change in Document Check-Out Status Action to the workflow.  This Action should be the first item executed in the workflow.

The item is currently locked for editing

The item is currently locked for editing

Why does this happen?  Assume the workflow is being triggered the millisecond that the form is being written to the library and not waiting for all the data to finish writing.

*Note* Once the form/item is unlocked, it might take a few minutes for the workflow timer to process the item.

PowerShell Get URL of SharePoint List or Library

How do you get the URL of a SharePoint List or Library?

I had hoped it was as simple as $List.URL or something close to that.

Here is how I solved it, and please let me know if you have a better way!


Add-PsSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue

$site = Get-SPweb "http://sharepointed.com/sites/blah"

$mList=$site.Lists["Tacos"]
 $ListURL = $site.url +"/"+ $mList.RootFolder.Url

$site.Dispose()

Update
Found a weird issue when trying to use $ListURL in a href tag. For some reason, if the list name had a space in it, anything after the first word would be dropped off in the link URL.

Example:
List Name: Real Big Taco
URL in href would be http://sharepointed.com/sites/blah/lists/Real

My fix:

 $ListURL = $site.url +"/"+ $mList.RootFolder.Url.ServerRelativeUrl.Replace(" ","%20")

Or as amac44 pointed out:
$list.ParentWeb.Url + ‘/’ + $list.RootFolder.Url

PowerShell Get SharePoint Person or Group Field

This one drove me CRAZY!

Simple question, how do you get people or groups from a SharePoint People or Group field.

Add-PsSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue

$site = Get-SPweb "http://www.sharepointed.com"

				$mList=$site.Lists["ListName"]
                                #you will want to provide a valid ID here:
				$item = $mList.GetItemById(<strong>"4"</strong>)
				$users=$item["MyPersonOrGroupField"]
				
				#build array of our Person or Groups
				$PeopleOrGroup = New-Object System.Collections.ArrayList
				
				If($PeopleOrGroup.Count -ge 0)
				{
					foreach($blah in $PeopleOrGroup)
						{
						 $parseUsr = $blah.ToString().Split('#')[1]
						 $PeopleOrGroup.add($parseUsr)					 
						}
				}

                                #now if you want to access our newly created array
                                Foreach($pg in $PeopleOrGroup)
                                {
                                     write-host $pg
                                }
                                


*Update*
Found another way to get this done!

foreach($blah in $PeopleOrGroup)
       {
	 $PeopleOrGroup.add($site.Users.GetByID($blah.LookupId))					 
       }

How to control permissions from a central List

Say you have  your site setup where every one of your customers has a sub site.  How could you easily manage the permissions on those sites?  What I have adopted is, creating a List where the sub sites are created from and managed.

Using the workflow actions from ilovesharepoint I’m doing the following.

1. Setup a Contact List (Customers) with these additional fields: Customer Site (Hyperlink), UserPermissions(Person or Group), Customer Status (Choice)

2. Using the ilovesharepoint Create a new site action, create a new customer site.  Using the Output variable of this action, write the URL to our Customer Site field.

3. Use the ilovesharepoint Execute PowerShell action to run our PowerShell script.


Add-PsSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue
 $site = Get-SPweb "http://www.sharepointed.com"

$mList=$site.Lists["Customers"]
 #Here you will want to add the ID of the item calling the workflow.
 #Simply remove [%Current Item:ID%], click on Add or Change Lookup, and add the ID field
 $item = $mList.GetItemById([%Current Item:ID%])
 $ActionType=$Item["Customer Status"]
 $CustomerSite= new-object Microsoft.SharePoint.SPFieldUrlValue($item["Customer Site"])
 $ClientSiteURL=$CustomerSite.URL
 $users=$item["UserPermissions"]

#build array of User Permissions
 $PowerUsr = New-Object System.Collections.ArrayList

foreach($usr in $users)
	{	 
						
		 $sUser = $usr.User
		 if($sUser -ne $null)
		 {
			$parseUsr = $site.SiteUsers.GetByID($usr.LookupId)
		 }
		 else
		 {
			$parseUsr = $usr.LookupValue
		 }
						 
		$PowerUsr.add($parseUsr)					 
	}

$web = Get-SPWeb $ClientSiteURL
$SDlist = $web.Lists["Shared Documents"]

#break role inheritance
 $SDlist.BreakRoleInheritance($true)

#remove all permissions from the List
 foreach ($assignment in $SDlist.RoleAssignments)
 {
 $assignment.RoleDefinitionBindings.RemoveAll();
 $assignment.Update();
 }

# Customer Status = Active
 If ($ActionType -eq "Active")
 {
 		if($PowerUsr.Count -ge 0)
		{
			foreach($Ausr in $PowerUsr)
				{
					$siteUsr = ""
					$account = ""
					$siteUsr = $site.SiteUsers[$Ausr]
					$siteGroup = $web.SiteGroups[$Ausr]
					
					if($siteUsr -ne $null)
					{
						$role = $web.RoleDefinitions["Read"]
						$assignment = New-Object Microsoft.SharePoint.SPRoleAssignment($siteUsr)
						$assignment.RoleDefinitionBindings.Add($role)
						$SDlist.RoleAssignments.Add($assignment)
						$web.RoleAssignments.Add($assignment)

					}
					else
					{
						$role = $web.RoleDefinitions["Read"]
						$assignment = New-Object Microsoft.SharePoint.SPRoleAssignment($siteGroup)
						$assignment.RoleDefinitionBindings.Add($role)
						$SDlist.RoleAssignments.Add($assignment)
						$web.RoleAssignments.Add($assignment)
					}
				}
		}
 }

# Customer Status = Not Active
 If ($ActionType -eq "Not Active")
 {
 if($PowerUsr.Count -ge 0)
 {
 foreach($Ausr in $PowerUsr)
 {
 $account = $web.SiteGroups[$Ausr]
 $role = $web.RoleDefinitions["Read"]

$assignment = New-Object Microsoft.SharePoint.SPRoleAssignment($account)
 $assignment.RoleDefinitionBindings.Add($role)
 $SDlist.RoleAssignments.Add($assignment)
 }
 }
 }

$SDlist.Update()
$web.Dispose()
$site.Dispose()

The script gets the URL of our sub site and permissions we are wanting to set on the Shared Documents library. By setting the Customer Status to Active or Not Active, the script will change the permissions accordingly.

*update*
Updated the script to work with users and groups.

Run Warmup Script on Startup

Recently ran across a SharePoint install that had links to all the web apps in the Startup folder on the WFE box.  First thought was, PowerShell that mess!

First you will need to create a batch file to call the PowerShell warmup script.  The batch file will need to live in your Startup folder. By doing this, the script will run on server startup.

*update*  what if you want to pause / delay the batch file? Simply add a “timeout /t 5” after the @echo off statement.  *remove the quotes and 5 is measured in seconds.*

@echo off
timeout /t 5
powershell.exe d:\PowerShellScripts\warmup.ps1

The PowerShell warmup script:


Add-PSSnapin Microsoft.SharePoint.PowerShell;

function Get-WebPage([string]$url)
{
 $wc = new-object net.webclient;
 $wc.credentials = [System.Net.CredentialCache]::DefaultCredentials;
 $pageContents = $wc.DownloadString($url);
 $wc.Dispose();
 return $pageContents;
}

Get-SPAlternateUrl -Zone Default | foreach-object {
 write-host $_.IncomingUrl;
 $html = Get-WebPage -url $_.IncomingUrl;
}

warmup script was created by Jon Badgett

http://www.jonthenerd.com/2011/04/19/easy-sharepoint-2010-warmup-script-using-powershell/