Archive

Posts Tagged ‘SP2010’

SharePoint 2010: Adding SAML Claim permission for All Authenticated Users using PowerShell.

February 1, 2017 Leave a comment

I recently had to convert one of my SharePoint 2010 Web Applications from using Windows Claims/NTLM to use SAML Claims, removing the need for NTLM authentication by using a Claims Provider (ADFS) for authentication. When doing so permissions on the SALM Claims Web Application broke because it was still leveraging the Windows Claims Permissions. Since the NTLM permission was removed at the Web Application level, and to meet the DISA STIG requirement Anonymous Access permissions were also removed; this in return restricted access to users who used to have “read” rights to the Portal. To fix this problem I had to grant the “read” permissions for the SAML Claims ‘All Authenticated Users’ to all Site Collections / Sites so these users can once again gain access. Below is how I accomplished this using PowerShell.

————————————————————————–

$webApp = Get-SPWebApplication "[WEB APPLICATION URL]"
$sts = Get-SPTrustedIdentityTokenIssuer "[CLAIMS PROVIDER TOKEN ISSUER NAME]"

$PermLevels = @{}

"URL `t" + "userName `t" + "userLogin `t" + "userEmail `t" + "permissionLevel `t" + "SAMLClaim" >> User_Permissions_AllAuthenticatedUsers.csv

foreach ($web in $webApp | Get-SPSite -Limit All | Get-SPWeb -Limit All)
{

	foreach ($role in $web.Roles)
	{
		$permmask = $role.PermissionMask
		$permname = $role.Name
		$PermLevels.Add("$permmask", "$permname")
		trap [Exception] {continue}
	}
	foreach ($perm in $web.Permissions)
	{
		$permmaskcurrent = $perm.PermissionMask
		$level = $PermLevels.Get_Item("$permmaskcurrent")

		if ($perm.Member.Name -like "*All Authenticated Users*")
		{
				#CLAIM PRINCIPAL FOR ROLE
				$claimPrincipal = New-SPClaimsPrincipal -ClaimValue $perm.Member.Name -ClaimType "http://schemas.microsoft.com/ws/2008/06/identity/claims/role" -TrustedIdentityTokenIssuer $sts
				
				
				$newUser = New-SPUser -UserAlias $claimPrincipal.ToEncodedString() -Web $web

				$account = $web.EnsureUser($newUser)
			
				if ($level -eq "Limited Access")
				{
					$level = "Read"
					$role = $web.RoleDefinitions[$level]
					$assignment = New-Object Microsoft.SharePoint.SPRoleAssignment($account)
					$assignment.RoleDefinitionBindings.Add($role)
					$web.RoleAssignments.Add($assignment)
				}
				else
				{
					$role = $web.RoleDefinitions[$level]
					$assignment = New-Object Microsoft.SharePoint.SPRoleAssignment($account)
					$assignment.RoleDefinitionBindings.Add($role)
					$web.RoleAssignments.Add($assignment)
				}
				
				$web.Url + "`t" + $perm.Member.Name + "`t" + $perm.Member.UserLogin + "`t" + $perm.Member.Email + "`t" + $level + "`t" + $account >> User_Permissions_AllAuthenticatedUsers.csv

		}
	}
}

————————————————————————–

The above script loops through all the Site Collections and Sites to search for the Windows Claim for ‘All Authenticated Users’ once it finds an instance where the ‘All Authenticated Users’ permissions is used it adds the SAML Claim for ‘All Authenticated Users’

This script does not clean up/remove the old Windows Claims permission for the ‘All Authenticated Users’ I did that just incase the Web Application needs to be extended to once again support Windows Claims/NTLM authentication.

I will later blog about how to add the ‘All Authenticated Users’ SAML Claim to Groups, and also how to add indivdual SAML Claim permissions to users by granting their SAML Token for email.

Hopefully this is helpful for those that are struggling to reprovision their Windows Claims permissions to SAML Claims.

SharePoint 2010: Enable (Page) Output Cache Settings using PowerShell

January 25, 2017 Leave a comment

To optimize performance in SharePoint 2010, there are a few settings you can do to help with page load times and optimizing SharePoint Cache.

The three main ways to do this is:

1. BLOB Cache
2. Object Cache
3. Page Output Cache

In my environment we are not leveraging BLOB cache, and Object Cache is already enabled by default. Though you can optimize it for your SP environment.

However the Page Output Cache is not enabled by default.

Below is a PowerShell script I created that enables the Page Output Cache at the Site Collection Level for a Web Application.

$webapp = Get-SPWebApplication [URL OF WEB APPLICATION]

foreach ($web in $webapp.Sites)
{
$cacheSettings = New-Object Microsoft.SharePoint.Publishing.SiteCacheSettingsWriter($web.url)
$cacheSettings.EnableCache = $true
$cacheSettings.Update();
Write-Host “Updated Page Output Cache Settings…” $web.Url
}

Options:

#Default Page Output Cache Profile. The Cache Profile Id is built off the Cache Profile List (Site Actions – Site Settings – Site Collection Cache Profiles (under Site Collection Administration))

SetAnonymousPageCacheProfileId($web.Url, 1)
SetAuthenticatedPageCacheProfileId($web.Url, 2);

#Page Output Cache Policy
$cacheSettings.AllowPublishingWebPageOverrides = $true;
$cacheSettings.AllowLayoutPageOverrides = $true;
$cacheSettings.EnableDebuggingOutput = $true;

SharePoint 2010: Getting SharePoint Claims Web Applications to Work With None-Claims Aware Applications / Services

February 19, 2016 Leave a comment

I recently ran into an issue with an in house solution that was developed in Visual Studio leveraging .NET and C# which made SOAP Web Service calls to SharePoint to populate form data from SharePoint lists.  This solution worked fine in my SharePoint 2007 environment that utilized Classic Authentication.  However after upgrading to SharePoint 2010 and switching the authentication type to Claims broke the ability for the solution to make successful SOAP Web Service calls to SharePoint.

So instead of me having to completely reengineer the in-house solution to be claims aware I took a different approach.

For me to successfully get this to work I had to do a few things.

ONE
1.  Extend the Claims Web Application to a new zone (intranet) that used Integrated  Windows Authentication (NTLM).  Give the Web Application a new name.  I used (SharePoint – Portal_NTLM)

Since extending the Web Application will keep the same Authentication mode of Claims as of the default primary Web Application I still had a little bit of work left to do.  I had to essentially “trick” the extended Web Application to think it was using Classic Authentication instead of Claims.

Since extending the Web Application creates a new web.config file I had to modify this file on each WFE Server for the new extended web app.  This is usually found in c:\inetpub\wwwroot\wss\VirtualDirectories\Extended Web Application

Open up the Web.Config File and search for the following lines
<add key=”aspnet:AllowAnonymousImpersonation” value=”true” />
Change to
<add key=”aspent:AllowAnonymousImpersonation” value=”false” />

Search for the following lines:
<authentication mode=”Forms”>
Change to
<authentication mode=”Windows”>

Make the changes to all web.config files and save.

TWO
Since the Default Web Application leveraged CLAIMS with Kerberos Authentication, and the Extended Web Application leveraged CLAIMS (hacked “Windows” in web.config) and NTLM Authentication the service account that ran the Application Pool for the Default Web Application did not have the necessary rights to call SOAP Web Services from within the in-house solution.  If I were to change the  Pass-Through Authentication in IIS for the Extended Site to use the “Connect As” and manually enter in the Farm Account and Password the in-house solution executed successfully, but I ran into another issue with NINTEX Workflows.  Since changing the Pass-Through Authentication to use “Connect As” it was using the Farm Account which when authenticating to SharePoint was signing in as the “System Account”  which broke the NINTEX Workflows from automatically kicking off because it was expecting a dedicated service account.

Since the Extended Web Application leveraged the same Application Pool as the Default (Main) Web Application I had to create a new Application Pool which used the Farm Account as the Identity.

For me to create a new Application Pool I had to do a few things.

I leveraged PowerShell to create a new Application Pool and associated that new Application Pool with the new extended web application:

Below is the PowerShell to create a new Application Pool and associate it with the extended Web Application.

Before you execute this PowerShell script make sure you write down the name of the original Web Application Pool name for the Default (Main) Web Application. *This will be important later*

————————————————————–

$WebAppURL = http://portal/extendedwebapp
$NewAppPoolName = “SharePoint – Portal_NTLM”
$NewAppPoolUserName = “DOMAIN\FarmAccount”

$Farm = Get-SPFarm
$Service = $Farm.Services | where {$_.TypeName -eq “Microsoft SharePoint Foundation Web Application”}
$Password = Read-Host -Prompt “Please enter your password” -AsSecureString
$NewAppPool = New-Object Microsoft.SharePoint.Administration.SPApplicationPool($NewAppPoolName,$Service)
$NewAppPool.CurrentIdentityType = “SpecificUser”
$NewAppPool.Username = $NewAppPoolUserName
$NewAppPool.SetPassword($Password)
$NewAppPool.Provision()
$NewAppPool.Update($true)

$NewAppPool = $Service.ApplicationPools[$NewAppPoolName]
$WebApp = Get-SPWebApplication $WebAppURL
$WebApp.ApplicationPool = $NewAppPool
$WebApp.ProvisionGlobally()
$WebApp.Update()

————————————————————–

After associating the new Extended Web Application to the new Application Pool I ran into one other problem.  Since the Extended Web Application shares the same Application Pool with the default (Main) Web Application, when doing this  it also re-associate the default (Main) Web Application with the new Application Pool.  Remember the note I mentioned up above “Before you execute this PowerShell script make sure you write down the name of the original Web Application Pool name for the Default (Main) Web Application. *This will be important later*”.   There is where this will now come into handy.  If your default (Main) Web Application utilizes Kerberos Authentication and the App Pool User Identity is different then that of the new Application Pool Identity you will run into problems.

To fix this problem you have to re-associate the default (Main) Web Application with its original App Pool.   To do this you basically run the same PowerShell script above minus the creation of the new Application Pool as follows:

————————————————————–
$Farm = Get-SPFarm
$Service = $Farm.Services | where {$_.TypeName -eq “Microsoft SharePoint Foundation Web Application”}
$NewAppPool = $Service.ApplicationPools[NAME OF DEFAULT APPLICATION POOL]
$WebApp = Get-SPWebApplication “URL OF THE DEFAULT WEB APPLICATON”
$WebApp.ApplicationPool = $NewAppPool
$WebApp.ProvisionGlobally()
$WebApp.Update()

————————————————————–

Now after running this script you will run into one last problem.  As mentioned above since the Extended Web Application shares the same Web Application Pool as the Default (Main) Web Application the Application Pool will again change for the Extended Web Application to use the Web Application Pool of the Default (Main) Web Application.  This is because the schema for the Web Application’s Application Pool lives within the ConfigDB.

If you execute the following two PowerShell lines below you will see which Web Applications are associated with which Web Application Pools:

$Farm = Get-SPFarm
$Service = $Farm.Services | where {$_.TypeName -eq “Microsoft SharePoint Foundation Web Application”}
$Service

You will notice that both the Default (Main) and the Extended Web Application are associated with the same Application Pool in the Config Database.  There is no way around associating the Extended Web Application to a new Application Pool and keeping the Default (Main) Web Application the same in the ConfigDB.  So you have to basically tell IIS to use a different Web Application Pool which basically bypasses what is associated in the ConfigDB.

Since now that there is a new Application Pool in IIS, you can now then manually re-associate the Extended Web Application Site to that new Web Application Pool.  This can only be done in IIS.  If you were to run the same two PowerShell scripts above you will still see the Extended Web Application is associated with the Default (Main) Web Application Pool, but will be assigned the new one in IIS.

Now the only problem with this is if you ever have to do any configuration of the Extended Web Application that might cause the reset of the Application Pool in IIS you have to again manually go back into IIS and re-associate the right Application pool to the Extended Web Application.

This was the way I was able to get an Extended Web Application to use Classic Authentication with NTLM from a Claims Authentication with Kerberos Web Application.

SharePoint 2010: Get InfoPath Browser Enabled Forms To Work With Claims Aware Web Applications

February 5, 2016 Leave a comment

In a recent upgrade from SharePoint 2007 to SP2010 we went from having a Web Application that used Classic Authentication to now using Claims Authentication (Claims Aware) in preparation for ADFS Federation in the future.  When doing so this broke the functionality of InfoPath Browser Enabled Forms from successfully executing SOAP Web Service calls.  This worked fine in the client but the browser enabled forms would not render the correct information when trying to populate fields while using the UserProfileService.asmx service and pulling in GetUserProfileByName properties.  To get InfoPath Browser Enabled Forms to Work with Claims Web Applications you have to do a few things.  Below are the steps needed to get this working in your environment.  The is lengthy with screenshots.

  1.  CREATE SECURE STORE SERVICE IN CENTRAL ADMIN
  2.  GENERATE NEW KEY
  3.  CREATE NEW APPLICATION ID FOR INFOPATH WEB SERVICES
    InfoPathWebServices_1
    InfoPathWebServices_3
    InfoPathWebServices_4
    InfoPathWebServices_5
  4. CREATE NEW INFOPATH 2010 FORM
    InfoPathWebServices_6
    DESIGN YOUR FORM, ADD A TEXTBOX CONTROL AND RENAME IT TO preferredName OR WHATEVER YOU CHOOSE
    InfoPathWebServices_7
    InfoPathWebServices_8
    CREATE DATA CONNECTION — GO TO “DATA” TAB IN THE RIBBON AND SELECT “FROM WEB SERVICE” THEN “FROM SOAP WEB SERVICE
    InfoPathWebServices_9
    CONNECT TO THE userprofileservice.asmx WEB SERVICE

    InfoPathWebServices_11
    SCROLL DOWN AND SELECT THE getuserbyprofilename ATTRIBUE AND CLICK NEXT
    InfoPathWebServices_12
    CLICK NEXT
    InfoPathWebServices_13
    CLICK NEXT
    InfoPathWebServices_14
    UNCHECK THE “Automatically retrieve data when form is open” CHECKBOX AND CLICK FINISH TO CREATE THE DATA CONNECTION
    InfoPathWebServices_15
  5. CREATE A NEW DATA COLLECTION LIBARY IN THE SHAREPOINT SITE WHERE YOUR INFOPATH FORM WILL LIVE
    InfoPathWebServices_16
  6. GO BACK TO INFOPATH AND EXPORT THE GetUserProfileByName DATA CONNECTION TO UDCX
    InfoPathWebServices_17
    BROWSE OR TYPE THE URL PATH OF THE DATA COLLECTION LIBRARY CREATED IN SHAREPOINT AND GIVE THE UDCX FILE A NAME OR KEEP DEFAULT FILE.UDCX AND CLICK “Ok”
    InfoPathWebServices_18
    GO BACK TO YOUR DATA COLLECTION LIBARARY IN SHAREPOINT AND THE UDCX FILE SHOULD NOW BE THERE
    InfoPathWebServices_19
    DOWNLOAD A LOCAL COPY OF THE UDCX FILE TO YOUR DESKTOP
    InfoPathWebServices_20
    OPEN UP THE LOCAL COPY OF THE FILE.UDCX FILE AND SEARCH FOR THE FOLLOWING LINE
    InfoPathWebServices_21
    UPDATE THE LINE AS FOLLOWS AND SAVE THE FILE.  REMEMBER TO DELETE THE LEADING “!–” AND TRIALING “
    InfoPathWebServices_22
    RE-UPLOAD THE FILE.UDCX FILE INTO THE DATA COLLECTION LIBRARY IN SHAREPOINT AND OVERWRITE THE EXISTING FILE
    InfoPathWebServices_23
  7. CREATE FORM LOAD RULES IN INFOPATH.
    GO BACK TO THE INFOPATH FORM AND CLICK ON THE “Data” TAB IN THE RIBBON AND SELECT “Form Load
    InfoPathWebServices_24
    THIS WILL LOAD THE FORM LOAD “RULES
    InfoPathWebServices_25
    CLICK “NEW” AND THEN “ACTION
    InfoPathWebServices_26
    GIVE THE RULE A NAME SUCH AS “Set User Profile” AND UNDER “Run these Actions:” CLICK “Add” AND SELECT “Set a field’s value
    InfoPathWebServices_27
    InfoPathWebServices_28
    CLICK THE TREE STRUCTURE BUTTON NEXT TO “Field“, CHANGE THE “Fields” DROP DOWN TO “GetUserProfileByName (Secondary)”.  EXPAND (myFields > queryFieldstns:GetUserProfileByName) AND SELECT “AccountName” AND CLICK “Ok
    InfoPathWebServices_29
    CLICK THE “Fx” BUTTON NEXT TO “Value”, AND ENTER IN THE FOLLOWING FORUMULA:  substring-after(username(), “i:0#.w|”) AND CLICK “Ok“, AND THEN “Ok” AGAIN.
    InfoPathWebServices_30
    BACK ON THE FORM LOAD RULES CLICK “Add” AND SELECT “Query for data
    InfoPathWebServices_31
    MAKE SURE “Action” IS SET TO “Query for data” and “Data Connection” IS SET TO “GetUserProfileByName“.  THIS SHOULD BE SET BY DEFAULT.  CLICK “Ok“.
    InfoPathWebServices_32
    BACK ON THE FORM LOAD RULES CLICK “Add” AND SELECT “Set a field’s value
    InfoPathWebServices_33
    CLICK THE TREE STRUCTURE BUTTON NEXT TO “Field“, KEEP THE “Fields” DROP DOWN TO “Main“.  EXPAND (myFields) AND SELECT “preferredName” AND CLICK “Ok
    InfoPathWebServices_35
    CLICK THE “Fx” BUTTON NEXT TO “Value“, AND CLICK THE “Insert Field or Group…” BUTTON.  CHANGE THE “Fields” DROPDOWN TO “GetUserProfileByName (Secondary)“.  EXPAND (dataFields>tns:GetUserProfileByNameResponse> GetUserProfileByNameResult> PropertyData>Values) AND SELECT “Value” AND CLICK THE “Filter Data…” BUTTON
    InfoPathWebServices_36
    NEXT CLICK THE “Add…” BUTTON AND CHANGE THE DROP DOWN FOR “Value” to “Select a field or group…
    InfoPathWebServices_37
    MAKE SURE THE DATA SOURCE IS STILL SET TO “GetUserProfileByName (Secondary)”.  SELECT “Name” FROM UNDER (dataFields> tns:GetUserProfileByNameResponse>GetUserProfileByNameResult > PropertyData) AND CLICK “Ok
    InfoPathWebServices_38
    IN THE SPECIFY FILTER CONDITION WINDOW, CHANGE THE BLANK DROP DOWN NEXT TO “Name is equal to” TO TYPE “Text
    InfoPathWebServices_39
    TYPE PreferredName IN THE BOX AND CLICK “OK” 4 TIMES
    InfoPathWebServices_40
    THE RULE DETAILS SHOULD NOW LOOK AS FOLLOWS.  IF SO, CLICK “OK
    InfoPathWebServices_42
    THE FORM LOAD RULES SHOULD NOW HAVE 3 ACTIONS.
    InfoPathWebServices_43
  8. PREVIEW YOUR INFOPATH FORM.  IF YOU FOLOWED THE STEPS ABOVE YOU SHOULD SEE YOUR ACCOUNT DISPLAYED IN THE FORM
    InfoPathWebServices_44
  9. IF THINGS WORKED AS EXPECTED.  TIME TO PUBLISH YOUR INFOPATH FORM TO SHAREPOINT.
    CLICK “File” SELECT “Publish” AND SELECT “SharePoint Server
    InfoPathWebServices_45
    TYPE IN THE URL OF THE SITE WHERE YOU WANT TO PUBLISH YOUR INFOPATH FORM.  THIS SHOULD BE HE SAME SITE WHERE YOU CREATED YOUR DATA COLLECTION LIBARARY.  CLICK “Next >”
    InfoPathWebServices_46
    STEP THROUGH THE WIZARD.  MAKE SURE THE “Enable this form to be filled out by using a browser” CHECK BOX IS CHECK, AND THE “Form Library” RADIO BUTTON SELECTED AND CLICK “Next >
    InfoPathWebServices_47
    STEP THROUGH THE WIZARD. ON THE NEXT SCREEN, IF YOU ALREADY HAVE A EXISTING FORM TEMPLATE LIBRARY SELECT THE “Update the form template in an existing form library” RADIO BUTTON AND SELECT YOUR LIBRARY.  FOR THIS CASE WE WILL KEEP THE “Create a new form library” RADIO BUTTON, AND CLICK “Next >“.
    InfoPathWebServices_48
    ON THE NEXT SCREEN, NAME YOUR FORM LIBRARY, AND GIVE A DESCRIPTION (OPTIONAL) AND CLICK “Next >“.
    InfoPathWebServices_49
    ON THE NEXT SCREEN, IF YOU WANT TO DISPLAY ANY FIELD COLUMNS IN YOUR SHAREPOINT FORM LIBRARY, CLICK “Add” AND ADD YOUR COLUMNS.  FOR THIS CASE WE WILL NOT ADD ANY COLUMNS, AND CLICK “Next >“.
    InfoPathWebServices_50
    VERIFY THE FORM INFORMATION AND CLICK “Publish
    InfoPathWebServices_52
    ONCE THE FORM IS PUBLISHED CLOSE OUT OF THE PUBLISHING WIZARD
    InfoPathWebServices_53
  10. TEST YOUR BROWSER ENABLED INFOPATH FORM IN SHAREPOINT

 

 

 

 

 

SharePoint 2010: Getting Claims Authentication Working with Windows Server 2012 SP2

January 14, 2016 Leave a comment

When configuring a new SharePoint 2010 Web Application with Claims Based Authentication in a Windows Server 2012 SP2 Platform I ran into some issues authenticating to the site.  Every time I tried to access the site I would be prompted for authentication even though I granted my account full control at the Web Application User Policy level.  I only ran into this issue with Claims Based Authentication activated at the Web Application level on Windows Server 2012 SP2, not on a Windows Server 2008 SP2 platform.  Windows Auth worked fine on both.  For me to resolve this issue I had to update the web.config file for that Web Application for AllowAnonymousImpersonation on each WFE.  This value needs to be set to false.

  1. On each SharePoint 2010 WFE Server open up the web.config file for the Web Application.  (c:\inetpub\wwwroot\wss\VirtualDirectories\web application)
  2. Do a cntrl+f and type in AllowAnonymous to find the <add key=”aspnet:AllowAnonymousImpersonation” value=”$true” />
  3. Change the value from $true to $false
  4. Save the web.config file
  5. Try to access your site again.

If you run into problems as I did try the steps above to help resolve the issue

 

SharePoint 2010: Get List of All Relative and Absolute URL’s in a Web Application using PowerShell

December 23, 2015 Leave a comment

In the process of configuring SharePoint 2010 to use ADFS Authentication I needed to extend the Web Application so that our external partners who are federated can access the portal with ADFS claims in a different zone, while our internal / non-federated users can still access the portal using Windows Auth with Kerberos.  When doing this you have to make sure there are no Absolute URL’s that might break the user experience.  Below is a PowerShell script I generated to search a Web Application for Relative and Absolute URLs so clean up can be performed before switching over to ADFS.

#GET WEB APPLICATION
$webApp = Get-SPWebApplication https://portal.com

#URL SEARCH STRING FOR ABSOLUTE URL
$searchURL = “*http*”

#CREATE .CSV FILE WITH HEADINGS FOR HYPERLINKS
“siteURL `t” + “Heading `t” + “hyperlink `t” + “Path” >> HYPERLINKS.csv

#FOREACH LOOP – LOOPS THROUGH ALL WEBS AND SUBSITES OF WEB APPLICATION
foreach ($web in $webApp | Get-SPSite -Limit All | Get-SPWeb -Limit All)

{
#GET PUBLISHING WEB FOR ALL WEBS IN WEB APPLICATION

$pubWeb = [Microsoft.SharePoint.Publishing.PublishingWeb]::GetPublishingWeb($web)
#GET GLOBAL NAVIGATION NODES
$nav = $pubWeb.Navigation.GlobalNavigationNodes
#GET QUICK LAUNCH NAVIGATION NODES

$nodes = $web.Navigation.QuickLaunch

#FOREACH LOOP – LOOPS THROUGH ALL GLOBAL NAVIGATION HEADINGS.
foreach ($qlHeading in $nav)

{
#GET GLOBAL NAVIGATION HEADING CHILDREN.

$qlLibraries = $qlHeading.Children

#FOREACH LOOP – LOOPS THROUGH ALL CHILDREN (LINKS) IN GLOBAL NAVIGATION HEADINGS.
foreach ($lib in $qlLibraries)

{
#IF STATEMENT TO CHECK IF HYPERLINK IS NOT NULL.

if ($lib.Url -ne $null)
{
write-host $qlHeading.Title
write-host $lib.Url
#IF STATEMENT TO CHECK HYPERLINK TO SEE IF IT MATCHES searchURL string.
if ($lib.Url -like $searchURL)

{
#IF HYPERLINK MATCHES THE $searchURL STRING THEN STORE “AbsoluteURL” STRING IN $path VARIABLE.

$path = “AbsoluteURL”
}
else
#IF HYPERLINK DOES NOT MATCH THE $searchURL  STRING THEN STORE “RelativeURL” STRING IN $path VARIABLE.

{
$path = “RelativeURL”
}
#WRITE GLOBAL NAVIGATION NODE RESULTS TO HYPERLINKS.csv FILE.

$web.Url + “`t” + $qlHeading.Title + “`t” + $lib.Url + “`t” + $path >> HYPERLINKS.csv
}
}
}
#FOREACH LOOP – LOOPS THROUGH ALL QUICK LAUNCH NAVIGATION NODES

foreach ($node in $nodes)
{
write-host $node.Title
write-host $node.Url
#IF STATEMENT TO CHECK HYPERLINK TO SEE IF IT MATCHES searchURL string.
if ($node.Url -like $searchURL)
{
#IF HYPERLINK MATCHES THE $searchURL STRING THEN STORE “AbsoluteURL” STRING IN $path VARIABLE.

$path = “AbsoluteURL”
}
else
{
#IF HYPERLINK DOES NOT MATCH THE $searchURL  STRING THEN STORE “RelativeURL” STRING IN $path VARIABLE.

$path = “RelativeURL”
}
#WRITE QUICK LAUNCH NAVIGATION NODE RESULTS TO HYPERLINKS.csv FILE.

$web.Url + “`t” + $qlHeading.Title + “`t” + $lib.Url + “`t” + $path >> HYPERLINKS.csv
}
}