I know, I know, I’m way behind on documenting my PowerShell cmdlets – I will be striving to get them done as soon as possible. I’ve already documented one of them, the Get-SPSite
cmdlet, and I will now continue with the Get-SPWeb
cmdlet. Hopefully I’ll be able to wrap up the others much quicker as they are a lot simpler – then I can finally start building new ones 🙂
Like the Get-SPSite
cmdlet the Get-SPWeb
cmdlet addresses some common issues found with working with SPWeb
objects. For additional details about the disposal problem when working with many common SharePoint objects via PowerShell see the post about the Get-SPSite
cmdlet. For those that aren’t familiar with the SPWeb object (Microsoft.SharePoint.SPWeb
), it’s the equivalent programmatic element for working with sites within site collections.
First lets look at the SPWebInfo
object and some its uses, the Get-SPWeb
cmdlet is extremely simple so I’ll save it for last. Consider the following code snippet:
1[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")
2$site = New-Object Microsoft.SharePoint.SPSite("http://portal")
3foreach ($web in $site.AllWebs) {
4 Write-Host $web.Url
5}
The above code results in a memory leak. If you don’t re-loop through each SPWeb object in the collection and dispose of the object by calling the Dispose()
method you will end up with unmanaged resources left in memory that could eventually cause issues if you do a lot of processing like this (eventually the GC will dispose of the objects but that could take quite some time). The same issue is true for the SPSite object.
Another option would be to use a different approach to get all the SPWeb objects within a site collection, an approach that can be used for more dynamic querying of objects and returns back an object that would not require disposal – an SPWebInfo
object. Here’s an example of how you could do something similar to the above using my Get-SPSite
cmdlet and the AllWebs
property that the SPSiteInfo
object exposes:
1$site = Get-SPSite("http://portal")
2foreach ($web in $site.AllWebs) {
3 Write-Host $web.Url
4}
The above code still uses the AllWebs property but in this case it’s part of my SPSiteInfo
object so rather than exposing a collection of SPWeb
objects it returns a collection of SPWebInfo
objects. As a result you no longer need to dispose of the objects returned.
The one obvious downside of this approach is that when you access the property I have to loop through all the webs internally and copy their data to my custom object before I can return back to the calling application. Typically though, we’re more concerned about flexibility and ease of use rather than performance when performing the simple administrative tasks that we’d be looking to perform using PowerShell.
What I like about the approach I put together is that I can now do filtered queries without having to worry about whether or not I disposed of the objects. Here’s an example of how to find all the webs that use a specific site template (in this case “STS”):
1$site = Get-SPSite("http://portal")
2$webs = $site.AllWebs | where -FilterScript {$_.WebTemplate -eq "STS"}
3foreach ($web in $webs) {
4 Write-Host $web.Url
5}
Or I can simply get a specific SPWebInfo
(and therefore the SPWeb
) object by calling the Get-SPWeb
cmdlet directly (I don’t currently support wildcards so this is only helpful for getting a specific web instance):
1$web = Get-SPWeb "http://devthekey"
2Write-Host $web.WebTemplate
It’s important to remember that the SPWebInfo
object is meant to be read-only as most of the properties are just copies of the variables but there are some exceptions such as the SPListCollection
object returned by the Lists property or the SPRecycleBinItemCollection
object returned by the RecycleBin
property. In general, if you have to call the Update()
method of the SPWeb object to save your changes then you have to use the actual SPWeb
object, otherwise you can work directly with the SPWebInfo
object and forego the need to instantiate and dispose of the SPWeb
object.
What about when you do need to access the actual SPWeb
object? There are two approaches for this: the first is to use the SPBase
property which will create a new SPWeb
instance and store that instance as a private member variable for future access to the property thus avoiding the overhead of creating another instance on subsequent calls; the second is to use the GetSPObject()
method which creates a new instance of the SPWeb
object but does not store a copy so it’s a nice easy way to get an entirely new instance of the actual SPWeb
object (useful for when you’ve made a change which requires a reload due to caching). In both cases you are responsible for disposing of the returned object.
The following code snippet shows the SPWebInfo
class:
1using System;
2using System.Collections;
3using System.Collections.Generic;
4using System.Globalization;
5using System.Linq;
6using System.Text;
7using System.Web.Configuration;
8using Microsoft.SharePoint;
9using Microsoft.SharePoint.Administration;
10using Microsoft.SharePoint.Navigation;
11using Microsoft.SharePoint.Utilities;
12using Microsoft.SharePoint.Workflow;
13
14namespace Lapointe.SharePoint.PowerShell.Commands.Proxies
15{
16 public class SPWebInfo : ISPInfo
17 {
18 private SPSite m_Site;
19 private SPWeb m_Web;
20 private List<SPWebInfo> m_Webs;
21 private Guid m_FirstUniqueAncestorWeb;
22 private Guid m_FirstUniqueRoleDefinitionWeb;
23 private SPListCollection m_Lists;
24 private SPListTemplateCollection m_ListTemplates;
25 private SPFeatureCollection m_Features;
26
27 internal SPWebInfo(SPWeb web)
28 {
29 ID = web.ID;
30 Alerts = web.Alerts;
31 AllowAnonymousAccess = web.AllowAnonymousAccess;
32 AllowAutomaticASPXPageIndexing = web.AllowAutomaticASPXPageIndexing;
33 AllowRssFeeds = web.AllowRssFeeds;
34 AllowUnsafeUpdates = web.AllowUnsafeUpdates;
35 AllProperties = web.AllProperties;
36 AllRolesForCurrentUser = web.AllRolesForCurrentUser;
37 AllUsers = web.AllUsers;
38 AllWebTemplatesAllowed = web.AllWebTemplatesAllowed;
39 AlternateCssUrl = web.AlternateCssUrl;
40 AlternateHeader = web.AlternateHeader;
41 AnonymousPermMask64 = web.AnonymousPermMask64;
42 AnonymousState = web.AnonymousState;
43 ASPXPageIndexed = web.ASPXPageIndexed;
44 ASPXPageIndexMode = web.ASPXPageIndexMode;
45 AssociatedGroups = web.AssociatedGroups;
46 AssociatedMemberGroup = web.AssociatedMemberGroup;
47 AssociatedOwnerGroup = web.AssociatedOwnerGroup;
48 AssociatedVisitorGroup = web.AssociatedVisitorGroup;
49 Audit = web.Audit;
50 AuthenticationMode = web.AuthenticationMode;
51 Author = web.Author;
52 AvailableContentTypes = web.AvailableContentTypes;
53 AvailableFields = web.AvailableFields;
54 CacheAllSchema = web.CacheAllSchema;
55 Configuration = web.Configuration;
56 ContentTypes = web.ContentTypes;
57 Created = web.Created;
58 CurrencyLocaleID = web.CurrencyLocaleID;
59 CurrentChangeToken = web.CurrentChangeToken;
60 CurrentUser = web.CurrentUser;
61 CustomMasterUrl = web.CustomMasterUrl;
62 DataRetrievalServicesSettings = web.DataRetrievalServicesSettings;
63 Description = web.Description;
64 try
65 {
66 DocTemplates = web.DocTemplates;
67 }
68 catch (SPException) {}
69 EffectiveBasePermissions = web.EffectiveBasePermissions;
70 EffectivePresenceEnabled = web.EffectivePresenceEnabled;
71 EventHandlersEnabled = web.EventHandlersEnabled;
72 EventReceivers = web.EventReceivers;
73 ExecuteUrl = web.ExecuteUrl;
74 Exists = web.Exists;
75 ExternalSecurityProviderSetting = web.ExternalSecurityProviderSetting;
76 Fields = web.Fields;
77 FieldTypeDefinitionCollection = web.FieldTypeDefinitionCollection;
78 Files = web.Files;
79 //FirstUniqueAncestor = web.FirstUniqueAncestor;
80 Folders = web.Folders;
81 Groups = web.Groups;
82 HasExternalSecurityProvider = web.HasExternalSecurityProvider;
83 HasUniqueRoleAssignments = web.HasUniqueRoleAssignments;
84 HasUniqueRoleDefinitions = web.HasUniqueRoleDefinitions;
85 IncludeSupportingFolders = web.IncludeSupportingFolders;
86 IsADAccountCreationMode = web.IsADAccountCreationMode;
87 IsADEmailEnabled = web.IsADEmailEnabled;
88 IsRootWeb = web.IsRootWeb;
89 Language = web.Language;
90 LastItemModifiedDate = web.LastItemModifiedDate;
91 Locale = web.Locale;
92 MasterUrl = web.MasterUrl;
93 Modules = web.Modules;
94 Name = web.Name;
95 Navigation = web.Navigation;
96 NoCrawl = web.NoCrawl;
97 //SPWeb ParentWeb = web;
98 ParentWebId = web.ParentWebId;
99 ParserEnabled = web.ParserEnabled;
100 PortalMember = web.PortalMember;
101 PortalName = web.PortalName;
102 PortalSubscriptionUrl = web.PortalSubscriptionUrl;
103 PortalUrl = web.PortalUrl;
104 PresenceEnabled = web.PresenceEnabled;
105 Properties = web.Properties;
106 Provisioned = web.Provisioned;
107 PublicFolderRootUrl = web.PublicFolderRootUrl;
108 QuickLaunchEnabled = web.QuickLaunchEnabled;
109 RecycleBin = web.RecycleBin;
110 RegionalSettings = web.RegionalSettings;
111 RequestAccessEmail = web.RequestAccessEmail;
112 RequestAccessEnabled = web.RequestAccessEnabled;
113 ReusableAcl = web.ReusableAcl;
114 RoleAssignments = web.RoleAssignments;
115 RoleDefinitions = web.RoleDefinitions;
116 RootFolder = web.RootFolder;
117 ServerRelativeUrl = web.ServerRelativeUrl;
118 Site = web.Site.ID;
119 SiteAdministrators = web.SiteAdministrators;
120 SiteGroups = web.SiteGroups;
121 SiteLogoDescription = web.SiteLogoDescription;
122 SiteLogoUrl = web.SiteLogoUrl;
123 SiteUserInfoList = web.SiteUserInfoList;
124 SiteUsers = web.SiteUsers;
125 SyndicationEnabled = web.SyndicationEnabled;
126 Theme = web.Theme;
127 ThemeCssUrl = web.ThemeCssUrl;
128 Title = web.Title;
129 TreeViewEnabled = web.TreeViewEnabled;
130 Url = web.Url;
131 UserIsSiteAdmin = web.UserIsSiteAdmin;
132 UserIsWebAdmin = web.UserIsWebAdmin;
133 Users = web.Users;
134 ViewStyles = web.ViewStyles;
135 //SPWebCollection Webs = web;
136 WebTemplate = web.WebTemplate;
137 WebTemplateId = web.WebTemplateId;
138 WorkflowTemplates = web.WorkflowTemplates;
139 }
140
141 /// <summary>
142 /// Returns a newly created instance of the object on the first access. Subsequent accesses will utilize an internal member variable.
143 /// The caller is responsible for disposing of the returned SPWeb object and it's parent SPSite object (web.Site.Dispose()).
144 /// </summary>
145 /// <value>The SP base.</value>
146 public IDisposable SPBase
147 {
148 get
149 {
150 if (m_Web == null)
151 {
152 if (m_Site == null)
153 m_Site = new SPSite(Site);
154
155 m_Web = m_Site.OpenWeb(ID);
156 }
157 return m_Web;
158 }
159 }
160
161 /// <summary>
162 /// Returns a newly created instance of the object every time without storing an internal member variable for subsequent access.
163 /// The caller is responsible for disposing of the returned SPWeb object and it's parent SPSite object (web.Site.Dispose()).
164 /// </summary>
165 /// <returns></returns>
166 public IDisposable GetSPObject()
167 {
168 return new SPSite(Site).OpenWeb(ID);
169 }
170
171 public SPAlertCollection Alerts { get; internal set; }
172 public bool AllowAnonymousAccess { get; internal set; }
173 public bool AllowAutomaticASPXPageIndexing { get; internal set; }
174 public bool AllowRssFeeds { get; internal set; }
175 public bool AllowUnsafeUpdates { get; internal set; }
176 public Hashtable AllProperties { get; internal set; }
177 public SPRoleDefinitionBindingCollection AllRolesForCurrentUser { get; internal set; }
178 public SPUserCollection AllUsers { get; internal set; }
179 public bool AllWebTemplatesAllowed { get; internal set; }
180 public string AlternateCssUrl { get; internal set; }
181 public string AlternateHeader { get; internal set; }
182 public SPBasePermissions AnonymousPermMask64 { get; internal set; }
183 public SPWeb.WebAnonymousState AnonymousState { get; internal set; }
184 public bool ASPXPageIndexed { get; internal set; }
185 public WebASPXPageIndexMode ASPXPageIndexMode { get; internal set; }
186 public IList<SPGroup> AssociatedGroups { get; internal set; }
187 public SPGroup AssociatedMemberGroup { get; internal set; }
188 public SPGroup AssociatedOwnerGroup { get; internal set; }
189 public SPGroup AssociatedVisitorGroup { get; internal set; }
190 public SPAudit Audit { get; internal set; }
191 public AuthenticationMode AuthenticationMode { get; internal set; }
192 public SPUser Author { get; internal set; }
193 public SPContentTypeCollection AvailableContentTypes { get; internal set; }
194 public SPFieldCollection AvailableFields { get; internal set; }
195 public bool CacheAllSchema { get; internal set; }
196 public short Configuration { get; internal set; }
197 public SPContentTypeCollection ContentTypes { get; internal set; }
198 public DateTime Created { get; internal set; }
199 public int CurrencyLocaleID { get; internal set; }
200 public SPChangeToken CurrentChangeToken { get; internal set; }
201 public SPUser CurrentUser { get; internal set; }
202 public string CustomMasterUrl { get; internal set; }
203 public SPDataRetrievalServicesSettings DataRetrievalServicesSettings { get; internal set; }
204 public string Description { get; internal set; }
205 public SPDocTemplateCollection DocTemplates { get; internal set; }
206 public SPBasePermissions EffectiveBasePermissions { get; internal set; }
207 public bool EffectivePresenceEnabled { get; internal set; }
208 public bool EventHandlersEnabled { get; internal set; }
209 public SPEventReceiverDefinitionCollection EventReceivers { get; internal set; }
210 public string ExecuteUrl { get; internal set; }
211 public bool Exists { get; internal set; }
212 public string ExternalSecurityProviderSetting { get; internal set; }
213 public SPFeatureCollection Features
214 {
215 get
216 {
217 if (m_Features != null)
218 return m_Features;
219
220 using (SPSite site = new SPSite(Site))
221 using (SPWeb web = site.OpenWeb(ID))
222 {
223 m_Features = web.Features;
224 }
225 return m_Features;
226
227 }
228 }
229 public SPFieldCollection Fields { get; internal set; }
230 public SPFieldTypeDefinitionCollection FieldTypeDefinitionCollection { get; internal set; }
231 public SPFileCollection Files { get; internal set; }
232 public Guid FirstUniqueAncestorWeb
233 {
234 get
235 {
236 if (m_FirstUniqueAncestorWeb != Guid.Empty)
237 return m_FirstUniqueAncestorWeb;
238
239 using (SPSite site = new SPSite(Site))
240 using (SPWeb web = site.OpenWeb(ID))
241 using (SPWeb ancestor = web.FirstUniqueAncestorWeb)
242 {
243 m_FirstUniqueAncestorWeb = ancestor.ID;
244 }
245 return m_FirstUniqueAncestorWeb;
246
247 }
248 }
249 public Guid FirstUniqueRoleDefinitionWeb
250 {
251 get
252 {
253 if (m_FirstUniqueRoleDefinitionWeb != Guid.Empty)
254 return m_FirstUniqueRoleDefinitionWeb;
255
256 using (SPSite site = new SPSite(Site))
257 using (SPWeb web = site.OpenWeb(ID))
258 using (SPWeb ancestor = web.FirstUniqueRoleDefinitionWeb)
259 {
260 m_FirstUniqueRoleDefinitionWeb = ancestor.ID;
261 }
262 return m_FirstUniqueRoleDefinitionWeb;
263
264 }
265 }
266 public SPFolderCollection Folders { get; internal set; }
267 public SPGroupCollection Groups { get; internal set; }
268 public bool HasExternalSecurityProvider { get; internal set; }
269 public bool HasUniqueRoleAssignments { get; internal set; }
270 public bool HasUniqueRoleDefinitions { get; internal set; }
271 public Guid ID { get; internal set; }
272 public bool IncludeSupportingFolders { get; internal set; }
273 public bool IsADAccountCreationMode { get; internal set; }
274 public bool IsADEmailEnabled { get; internal set; }
275 public bool IsRootWeb { get; internal set; }
276 public uint Language { get; internal set; }
277 public DateTime LastItemModifiedDate { get; internal set; }
278 public SPListCollection Lists
279 {
280 get
281 {
282 if (m_Lists != null)
283 return m_Lists;
284
285 using (SPSite site = new SPSite(Site))
286 using (SPWeb web = site.OpenWeb(ID))
287 {
288 m_Lists = web.Lists;
289 }
290 return m_Lists;
291
292 }
293 }
294 public SPListTemplateCollection ListTemplates
295 {
296 get
297 {
298 if (m_ListTemplates != null)
299 return m_ListTemplates;
300
301 using (SPSite site = new SPSite(Site))
302 using (SPWeb web = site.OpenWeb(ID))
303 {
304 m_ListTemplates = web.ListTemplates;
305 }
306 return m_ListTemplates;
307
308 }
309 }
310 public CultureInfo Locale { get; internal set; }
311 public string MasterUrl { get; internal set; }
312 public SPModuleCollection Modules { get; internal set; }
313 public string Name { get; internal set; }
314 public SPNavigation Navigation { get; internal set; }
315 public bool NoCrawl { get; internal set; }
316 public SPWeb ParentWeb { get; internal set; }
317 public Guid ParentWebId { get; internal set; }
318 public bool ParserEnabled { get; internal set; }
319 public bool PortalMember { get; internal set; }
320 public string PortalName { get; internal set; }
321 public string PortalSubscriptionUrl { get; internal set; }
322 public string PortalUrl { get; internal set; }
323 public bool PresenceEnabled { get; internal set; }
324 public SPPropertyBag Properties { get; internal set; }
325 public bool Provisioned { get; internal set; }
326 public string PublicFolderRootUrl { get; internal set; }
327 public bool QuickLaunchEnabled { get; internal set; }
328 public SPRecycleBinItemCollection RecycleBin { get; internal set; }
329 public SPRegionalSettings RegionalSettings { get; internal set; }
330 public string RequestAccessEmail { get; internal set; }
331 public bool RequestAccessEnabled { get; internal set; }
332 public SPReusableAcl ReusableAcl { get; internal set; }
333 public SPRoleAssignmentCollection RoleAssignments { get; internal set; }
334 public SPRoleDefinitionCollection RoleDefinitions { get; internal set; }
335 public SPFolder RootFolder { get; internal set; }
336 public string ServerRelativeUrl { get; internal set; }
337 public Guid Site { get; internal set; }
338 public SPUserCollection SiteAdministrators { get; internal set; }
339 public SPGroupCollection SiteGroups { get; internal set; }
340 public string SiteLogoDescription { get; internal set; }
341 public string SiteLogoUrl { get; internal set; }
342 public SPList SiteUserInfoList { get; internal set; }
343 public SPUserCollection SiteUsers { get; internal set; }
344 public bool SyndicationEnabled { get; internal set; }
345 public string Theme { get; internal set; }
346 public string ThemeCssUrl { get; internal set; }
347 public string Title { get; internal set; }
348 public bool TreeViewEnabled { get; internal set; }
349 public string Url { get; internal set; }
350 public bool UserIsSiteAdmin { get; internal set; }
351 public bool UserIsWebAdmin { get; internal set; }
352 public SPUserCollection Users { get; internal set; }
353 public SPViewStyleCollection ViewStyles { get; internal set; }
354 public List<SPWebInfo> Webs
355 {
356 get
357 {
358 if (m_Webs != null)
359 return m_Webs;
360
361 m_Webs = new List<SPWebInfo>();
362 using (SPSite site = new SPSite(Site))
363 using (SPWeb web = site.OpenWeb(ID))
364 {
365 foreach (SPWeb subWeb in web.Webs)
366 {
367 try
368 {
369 m_Webs.Add(new SPWebInfo(subWeb));
370 }
371 finally
372 {
373 subWeb.Dispose();
374 }
375 }
376 }
377 return m_Webs;
378
379 }
380 }
381 public string WebTemplate { get; internal set; }
382 public int WebTemplateId { get; internal set; }
383 public SPWorkflowTemplateCollection WorkflowTemplates { get; internal set; }
384 }
385}
The following is the code of the core Get-SPWeb
cmdlet:
1using System;
2using System.Collections.Generic;
3using System.Management.Automation;
4using Lapointe.SharePoint.PowerShell.Commands.OperationHelpers;
5using Lapointe.SharePoint.PowerShell.Commands.Proxies;
6using Lapointe.SharePoint.PowerShell.Commands.Validators;
7using Lapointe.SharePoint.STSADM.Commands.OperationHelpers;
8using Microsoft.SharePoint;
9
10namespace Lapointe.SharePoint.PowerShell.Commands.Webs
11{
12 [Cmdlet(VerbsCommon.Get, "SPWeb", SupportsShouldProcess=true, DefaultParameterSetName = "Url")]
13 public class GetSPWebCommand : PSCmdletBase
14 {
15 /// <summary>
16 /// Gets or sets the URL.
17 /// </summary>
18 /// <value>The URL.</value>
19 [Parameter(
20 ParameterSetName = "Url",
21 Mandatory = true,
22 Position = 0,
23 ValueFromPipeline = true,
24 ValueFromPipelineByPropertyName = true,
25 HelpMessage = "The URL of the web to return")]
26 [ValidateNotNullOrEmpty]
27 [ValidateUrl(false)]
28 public string[] Url { get; set; }
29
30
31 /// <summary>
32 /// Processes the record.
33 /// </summary>
34 protected override void ProcessRecordEx()
35 {
36 foreach (string url in Url)
37 {
38 string siteUrl = url.TrimEnd('/');
39 using (SPSite site = new SPSite(siteUrl))
40 using (SPWeb web = site.AllWebs[Utilities.GetServerRelUrlFromFullUrl(siteUrl)])
41 {
42 WriteObject(new SPWebInfo(web));
43 }
44 }
45 }
46 }
47}
The following is the full help for the cmdlet.
PS C:\> get-help get-spweb -full
NAME
Get-SPWeb
SYNOPSIS
Gets one or more SPWebInfo objects representing a SharePoint 2007 Web.
SYNTAX
Get-SPWeb [-Url] <String[]> [-WhatIf] [-Confirm] [<CommonParameters>]
DETAILED DESCRIPTION
Pass in a comma separated list of URLs or a string array of URLs to obtain a collection of SPWebInfo objects. Thes
e objects do not need to be disposed.
The SPWebInfo object that is returned contains almost all of the same properties of the SPWeb object but does not r
equire disposal and should be generally considered read-only. You can get to the actual SPWeb object by using the
SPBase property or the GetSPObject() method. The SPBase property results in a copy of the SPWeb object being persi
sted in the SPWebInfo object for faster access on future calls. Always remember to dispose of the SPWeb object if
used. Some collection properties may be directly updated without the need to access the SPSite object.
Copyright 2008 Gary Lapointe
> For more information on these PowerShell cmdlets:
> http://www.falchionconsulting.com/
> Use of these cmdlets is at your own risk.
> Gary Lapointe assumes no liability.
PARAMETERS
-Url <String[]>
Specifies the URL of the web(s) to retrieve. Wildcards are not permitted. If you specify multiple URLs, use com
mas to separate the URLs.
Required? true
Position? 1
Default value
Accept pipeline input? true (ByValue, ByPropertyName)
Accept wildcard characters? false
-WhatIf
Required? false
Position? named
Default value
Accept pipeline input? false
Accept wildcard characters? false
-Confirm
Required? false
Position? named
Default value
Accept pipeline input? false
Accept wildcard characters? false
<CommonParameters>
This cmdlet supports the common parameters: -Verbose, -Debug,
-ErrorAction, -ErrorVariable, and -OutVariable. For more information,
type, "get-help about_commonparameters".
INPUT TYPE
String
RETURN TYPE
Collection of SPWebInfo objects.
NOTES
For more information, type "Get-Help Get-SPWeb -detailed". For technical information, type "Get-Help Get-SPW
eb -full".
-------------- EXAMPLE 1 --------------
C:\PS>$web = get-spweb -url http://portal
This example returns back a single SPWebInfo object.
RELATED LINKS
http://www.falchionconsulting.com
Note that if you receive an exception during the execution of this cmdlet simply pass in the -debug
parameter in order to display the full stack trace which you can use to either debug yourself or report back to here to help me improve the code.