Using PowerShell to test for broken URL redirects

This PowerShell script iterates through a list of URLS from a CSV file looking for broken redirects. If any are found they are noted to a file.

#------------------------------------------------------------
 cls
 #------------------------------------------------------------
 # BEGIN: Config
 #------------------------------------------------------------
 # Where are the files?
 $path = "C:\checkLinks"; # Do NOT end with \
 # Source
 $csv = import-csv -Path "$path\source.csv";
 # Report
 $targetFile = "report.csv";
 # Where does the site send you to if a link is broken?  Look at "OriginalString" in code as it's possibly not what you assume it is.
 $redirStr = "/error";
 # What is the name of the column in the CSV file that has the URLs?
 $urlColumn = "url";
 #------------------------------------------------------------
 # END: Config
 #------------------------------------------------------------

#------------------------------------------------------------
 # BEGIN: SUPPORTING FUNCTIONS
 #------------------------------------------------------------

#============================================================
 # BEGIN: Get-URL
 # DESC: Receives params, checks URL for redirect and if redirect
 # matches str writes to report file.
 #============================================================
 function Get-URL {
 param([string]$url)
 try
 {
 "Checking: $url"
 #========================================================
 $wr = [System.Net.HttpWebRequest]::Create($url);
 $wrRsp = $wr.GetResponse();
 $temp = $wrRsp.ResponseUri.AbsolutePath
 $redirectURL = $wrRsp.ResponseUri.OriginalString
 $redirectURL
 if ($temp -like $redirStr) {
 Add-Content $path\$targetFile "$url"
 };
 $wrRsp.Close();
 #========================================================
 } catch {
 $errorStatus = "Exception Message: " + $_.Exception.Message;
 Write-Host $errorStatus;
 }
 };
 #============================================================
 # END: Get-URL
 #============================================================

#------------------------------------------------------------
 # END: SUPPORTING FUNCTIONS
 #------------------------------------------------------------

#============================================================
 # START MAIN
 #============================================================

#============================================================
 # BEGIN: Step 1
 #============================================================
 # A: Go to folder
 cd $path
 # B: Does report file exist? If no, create it.
 if (!(Test-Path "$path\$targetFile")) {
 New-Item -path $path -name $targetFile -type "file"
 };
 #============================================================
 # END: Step 1
 #============================================================

#============================================================
 # BEGIN: Step 2
 #============================================================
 foreach($line in $csv)
 {

# Loop through each row and check if URL has value.
 $properties = $line | Get-Member -MemberType Properties
 for($i=0; $i -lt $properties.Count;$i++)
 {
 $column = $properties[$i]
 $columnvalue = $line | Select -ExpandProperty $column.Name

#-----------------------------------------------------
 # BEGIN: Send to check URL
 #-----------------------------------------------------
 if ($column.Name -eq $urlColumn){
 if ($columnvalue.Length -gt 4){
 Get-URL $columnvalue;
 };
 };
 #-----------------------------------------------------
 # END: Send to check URL
 #-----------------------------------------------------

    };
 };
 #============================================================
 # END: Step 2
 #============================================================

 

SharePoint list item popovers on hover with AngularJS

Here’s how you can create Bootstrap style popovers of SharePoint list items using AngularJS.

<!DOCTYPE html>
<head>
<link rel=”stylesheet” href=”bootstrap.css” />
<link rel=”stylesheet” href=”font-awesome.css” />

<script type=”text/javascript” src=”modernizr.custom.js”></script>
<script type=”text/javascript” src=”jquery.js”></script>
<script type=”text/javascript” src=”angular.min.js”></script>
<script type=”text/javascript” src=”bootstrap.js”></script>
<script type=”text/javascript” src=”ui-bootstrap-tpls.min.js”></script>

</head>
<body ng-app=”toolTips”>

<div ng-controller=”mainController”>
<table>
<tr ng-repeat=”faq in faqs” bs-popover>
<td>
<a href=”#” data-popover=”true” rel=”popover” data-content=”{{faq.Body}}” data-original-title=”{{faq.Title}}”>
{{faq.Title}}
</a>
</td>
</tr>
</table>
</div>

<script type=”text/javascript”>
var app = angular.module(‘toolTips’, [‘ui.bootstrap’]);
app.controller(‘mainController’, function($scope, $http, $sce) {

$http({
method: ‘GET’,
url: “/_api/web/lists/getByTitle(‘someList)/items?$orderby=Title asc”,
cache: true,
headers: { “Accept”: “application/json;odata=verbose” }
}).success(function (data, status, headers, config) {
$scope.faqs = data.d.results;
//$scope.trustAsHtml = $sce.trustAsHtml;
$(“#contentLoading”).hide();

}).error(function (data, status, headers, config) {

});

});

app.directive(‘bsPopover’, function() {
return function(scope, element, attrs) {
element.find(“a[rel=popover]”).popover({ placement: ‘bottom’, html: ‘true’});
};
});

$(‘body’).popover({ selector: ‘[data-popover]’, trigger: ‘click hover’, placement: ‘auto’, delay: {show: 50, hide: 2000}});
</script>

</body>
</html>

 

Using stacktrace.js to log AngularJS errors to a SharePoint list

stacktrace.js: is a Framework-agnostic, micro-library for getting stack traces in all web browsers allowing you to debug your JavaScript by giving you a nicely detailed stack trace of function calls leading to an error (or any condition you specify).

http://www.stacktracejs.com/


1: Create a new list, in this example we will call it “apperrors” and it will be at the root. Create the following columns:

  • errorMessage as multiple lines without formatting.
  • stackTrace as multiple lines without formatting.

2: First include stacktrace.js after your AngularJS script.

<script type=”text/javascript” src=”angular-1.3.15/angular.min.js”></script>
<script type=”text/javascript” src=”stacktrace.min.js”></script>

3: By default AngularJS catches errors and log them verbosely to the console. This is highly desirable so we will keep that behavior and just add an interception in so that we can use stacktrace.js to centrally log any errors.

app.provider(“$exceptionHandler”, {
    $get: function( errorLogService ) {
        return( errorLogService );
    }
});

4: Even though since step 1 stacktrace.js is now in the global scope it is not ‘correct’ to reference a global object inside an AngularJS component. Therefore the stacktrace feature needs to be wrapped in an AngularJS service that will expose the print method.

app.factory(“stacktraceService”, function() {
    return({
        print: printStackTrace
    });

});

5: The error logging service is a wrapper around the core error handling of AngularJS.

app.factory(“errorLogService”, function( $log, $window, stacktraceService ) {
    function log( exception, cause ) {
        $log.error.apply( $log, arguments );
        try {
            var URL = window.location.href;
            var errorMessage = JSON.stringify(exception.toString());
            var stackTrace = JSON.stringify(stacktraceService.print({ e: exception }));
            var item = {
                “__metadata”: { “type”: “SP.Data.apperrorsListItem”},
                “Title”: URL,
                “errorMessage”: errorMessage,
                “stackTrace”: stackTrace
            };
            $.ajax({
                url: _spPageContextInfo.webAbsoluteUrl + “/_api/web/lists/getbytitle(‘apperrors’)/items”,
                type: “POST”,
                contentType: “application/json;odata=verbose”,
                data: JSON.stringify(item),
                headers: {
                        “Accept”: “application/json;odata=verbose”,
                       “X-RequestDigest”: $(“#__REQUESTDIGEST”).val()
                },
                success: function (data) {
                    console.log(JSON.stringify(data, null, 4));
                },
                error: function (data) {
                    console.log(JSON.stringify(data, null, 4));
                }
            });
            } catch ( loggingError ) {
                $log.warn( “Error logging failed” );
                $log.log( loggingError );
            }
    }
    // Return the logging function.
    return( log );
});

5: That’s it. In theory if all has gone correctly any AngularJS errors will now get written to the SharePoint list.

http://www.bennadel.com/blog/2542-logging-client-side-errors-with-angularjs-and-stacktrace-js.htm

https://angularjs.org/

http://www.stacktracejs.com/

SharePoint PowerShell script to check if a site collection is alive and email if not.

This might help somebody. In brief the script checks the array of URLs and if it gets a non 200 (OK) response back it emails out an alert. It can also be used as a keep alive script. Best run on a non farm connected server.

$urls= @("http://webapp/sitecollection1/Default.aspx",

"http://webapp/sitecollection2/default.aspx",

"http://webapp/sitecollection3/default.aspx",

"http://webapp/sitecollection4/default.aspx");

# Request all URLs in the array

foreach ($objItemin$urls) {

Write-Host“Checking $objItem”;

$req= [system.Net.WebRequest]::Create($objItem)

$req.UseDefaultCredentials=$true

try {

$res=$req.GetResponse()

} catch [System.Net.WebException] {

$res=$_.Exception.Response

}

$int= [int]$res.StatusCode

$status=$res.StatusCode

write-host“$int $status”

if ($int-ne 200) {

Write-Host”  Sending Email…”;

$enc  =New-ObjectSystem.Text.utf8encoding;

$smtp=”emailserver.domain.com”;

$to=”Recipient 1<username@domain.com>”;

$toCC=Recipient 2 <username@domain.com>”;

$from=”SharePoint farm <username@domain.com>”;

$ScriptName=$MyInvocation.MyCommand.Name;

$scriptPath=split-path-parent$MyInvocation.MyCommand.Definition;

$body=”This was generated by the script $ScriptName in $scriptPath”;

$subject=”URL check failure on $objItem – ‘$int : $status'”;

send-MailMessage-SmtpServer$smtp-To$to-Cc$toCC-From$from-Subject$subject-Body$body-BodyAsHtml-Encoding$enc;

Write-Host”  Sent.”;

}

}

Using AppFabric Distributed Cache on SharePoint 2013

After encountering some issues I thought I’d post a few bullets that may help someone.  They mostly cover memory and things to not do.

How to import your IIS logs into Piwik

Piwik is pretty awesome if you’re in the market for the functionality it provides. Unfortunately a lot of people who use IIS, SharePoint, .NET are not familiar with Python and may struggle with getting their IIS logs into Piwik. This should help if you are in that situation.

  1. Move your logs to a central location. PowerShell as a scheduled job is perfect for this. In this example let us assume it is D:LOGS
  2. Let us also assume that you are running Piwik on the local machine aka localhost on port 1000 and the ID of the site in Piwik is 1. These values are in the code below.
  3. Create a script called importFiles.py and paste the below into it. The TAB indents are pretty important.

import os, fnmatch, subprocess

def find_files(directory, pattern):
    for root, dirs, files in os.walk(directory):
        for basename in files:
            if fnmatch.fnmatch(basename, pattern):
                filename = os.path.join(root, basename)
                yield filename

for filename in find_files(‘C:LOGS’, ‘*.log’):
    #print (filename)
    os.system(“C:/inetpub/wwwroot/Piwik/misc/log-analytics/import_logs.py –url=http://localhost:1000/ ” +str(filename) +” –idsite=1″)

Notes about the above.

  • You must NOT install Python 3.x. Install 2.x. This is a compatibility issue with Piwik.
  • I use MariaDB. If you are not familiar with it think of it as simply as it being a fully compatible fork of MySQL.
  • You can definitely optimize this script further by reading the Piwik docs. This is about as basic as it can be and still get the job done.
  • This is recursive so if you are moving the logs into server named subfolders, a good idea if you have a farm, it should work just fine.
  • I would strongly recommend that you move the files to a “processed” folder outside of the path above once you’re done. 
  • Make sure to set index.php as your default document in the IIS site you are running Piwik from.
If you need to do over then you need to get the log file data out of the DB. to do so remove the appropriate tables and delete the appropriate values similar to below. More details are in the Piwik FAQ here.
DROP TABLE piwik_archive_numeric_2011_01, piwik_archive_numeric_XX;
DELETE FROM piwik_log_visit WHERE idsite = X;
DELETE FROM piwik_log_link_visit_action WHERE idsite
= X;
DELETE FROM piwik_log_conversion WHERE idsite
= X;
DELETE FROM piwik_log_conversion_item WHERE idsite
= X;
More info and relevant downloads can be gotten here: