Harald S. Fianbakken on January 19th, 2012

Often it’s useful to perform batch operations on a set of files matching some criteria.

Some usages:

  1. Move (and delete) old logs
  2. Make backups of all new files
  3. Scan files for patterns

The sample script below can be used to do just that. Using the Get-ChildItem with recurse and filter allows you to get a file list.

Using Where-Object (?) will filter based on any criteria on the FileInfo objects in your list (lookup .NET properties on this type for additional filtering info). Check out http://msdn.microsoft.com/en-us/library/system.io.fileinfo.aspx for properties you can use on file-objects.

In the Foreach-Object (%) you can do whatever operation you want, e.g. move them to another location and prefix them.

Feel free to modify it to your needs. Enjoy;)

# Simple archiving script 
# Author: Harald S. Fianbakken < Fianbakken.com > 

# Get a list of all files from a folder - recurse (check all in all subfolders)
$oldLogs = gci c:\Windows -filter *.txt -recurse
# Filter them - I'm intr in logs that was last written to 7 days ago. Could actually check last accessed instead.
$logsOlderThanWeek = $oldLogs|?{$_.LastWriteTime -lt [System.DateTime]::Now.Subtract([System.TimeSpan]::FromDays(7))}

#Print logs (just as a debug)
$logsOlderThanWeek
# Do something about them - Eg. move them to a temp location and postfix them with -old

$logsOlderThanWeek|%{
  $logName= $_.Name
  mv $_.FullName "C:\Temp\${logName}-old"  
}

									

Tags: ,

Harald S. Fianbakken on January 17th, 2012

A neat little helper method to type-safe cast an object to another type.

NB: The input object must implement IConvertible.

    public static T ToValue<T>(this object value)
        {
                return (T) Convert.ChangeType(value, typeof (T));
        }
									

Tags: ,

Harald S. Fianbakken on January 10th, 2012

Whatever IDE you are using, or language for that matter, deploying files to different servers can be really boring (and repetative).

In many cases your IDE has built-in support for deployment – but usually just for one server – and little flexible.  The deployment/publishing features within your IDE does not always match the structure you require from your structure.

I’ve often had the need to be able to :

  • Update my files from SVN
  • Copy certain files from a base location to different remote locations
  • Be able to specify / ignore certain files (e.g. test – files from my solution that only makes sense on local development environment)
  • Upload the same files and structure to multiple servers.

As I hate manual work, I wrote this script where you can configure the following:

  • SVNRoot – Base folder for svn updates / checkouts
  • Folders (from this base) that will be scanned for files
  • File patterns to be scanned (recursively from the above folders) – E.g *.aspx, *.ascx, *.dll
  • File patterns to be ignored (e.g. all files containing _Test_aspx).
  • Folder patterns to be ignored (all files in these folders will be ignored)
  • Web.config for deployment (if needed for webservers)
  • Target servers – multiple ftp servers for uploading
  • Ftp user and password for deployment

If something else than FTP should be used for transferring, it should be fairly easy to rewrite this script.

Script explained (Download script and configure it):

  • Updates your SVNRoot directory (svn) – requires SVN to be installed
  • Start-Upload is called (main-method for starting the process)
  • Iterates your configured folders
  • For each folder : Scans for the configured filetypes (recursively) – removes the folders that should be ignored
  • If file is valid (should not be ignored), constructs a relative path based on SVNRoot and base of the folder it’s within and uploads the file by calling Upload-File ($localFile, $relativeDestination).
  • For each file that should be uploads – executes a System.Net.WebClient.UploadFile (PUT) to each of the configured servers

Should be fairly easy to configure and adjust for other systems than FTP. Note that the FTP solution here requires the folder structure to be present on the FTP servers. If not, the script will just show an error message for each file that could not be uploaded through the webclient.

# Simple publishing script 
# Author: Harald S. Fianbakken <harald@Fianbakken.com>
# Why: Cause I'm to lazy to checkout files and upload them to respective servers
# NB: Folder structure must be present on FTP server - Make sure to do this in advance
# If not present, the WebClient will fail for each file trying to be uploaded.

# BEGIN SCRIPT CONFIGURATION

# Root folder where files are checked in / out
$SVNRoot = "C:\VS\Fianbakken\MyProject\Fianbakken.CoreProjects\"

# This is usually the targets you'd want to configure
# Files are fetched from these directories according the the pattern specified below 
$baseFolders = "${SVNRoot}Fianbakken.FrontEnd\Fianbakken.FrontEnd.Main", "${SVNRoot}Fianbakken.FrontEnd\Fianbakken.FrontEnd.Main\Content"
# What file types to we wish to upload - Disable all irrelevant files for faster deployment
$filesToUpload = "*.dll", "*.ascx", "*.aspx", "*.css", "*.js"
# If you just want to test the script or upload single file uncomment the following and replace with a valid filename
#$filesToUpload = "Bootstrap.js"

# Should configuration file be deployed (performs iis-reset!)
$deployConfig = $false;
$configToUpload = "$SVNRoot\Doc\Web.Config"
$configDeploymentTarget ="/Web.Config" # Root path of server

# Folders will be ignored (and all its contents)
# NB: These are relative paths (relative to each baseFolder)
$foldersToIgnore = "/obj/", "/Content/"

# What files (and patterns) to skip. Each item will be matched with contains (wilcard)
# This will make all files containing _Test_.aspx to be ignored (not uploaded)
$filesToIgnore = "_Test_.aspx"

# FTP settings where files are to be uploaded
$ftpUser = "myuser"
$ftpPassword = "blabla"
$targetServers = "publish.Fianbakken.com", "cms.Fianbakken.com"
$targetBaseFolder = "www.Fianbakken.com"

# END SCRIPT CONFIGURATION

# DO NOT MODIFY BELOW THIS LINE
# TODO - Could parse SVN response to only update these files!
svn update $SVNRoot 


$connections = @{}
$client = New-Object System.Net.WebClient


function Get-FtpUrl($relativeFilePath, $server){
    $url = "ftp://${ftpUser}:${ftpPassword}@$server/${targetBaseFolder}${relativeFilePath}"    
    return $url
}

function Upload-File($localFile, $relativeDestination){
    
    $targetServers | % {
        $url = Get-FtpUrl -relativeFilePath $relativeDestination -server $_
        $outstring = $url.Replace($ftpPassword, "********")
        Write-Host -ForegroundColor Green "Uploading $localFile to $_ "
        Write-Host -ForegroundColor Gray " |-- PUT $outstring"        
        $data = $client.UploadFile($url, $localFile);
     
    }
    
    # To Download, use DownloadFile $dest, $lcoal

}


# Fetches files for uploading and does the magic
function Start-Upload(){

    if($deployConfig){
        Write-Host -ForegroundColor Green "Uploading configuration file!"
        Upload-File -localFile $configToUpload -remoteDestination $configDeploymentTarget
    }
    # Done with config
    $baseFolders | % {
        if($_ -ne $null){
            $base = $_;
            $items = gci -Include $filesToUpload -Recurse -Path $base;
            $items | % {
                if($_ -ne $null){
                    # Fix paths , make it relative
                    $theFile = $_.Fullname;
                    $relativePath = $theFile.Replace($base, "");
                    $relativePath = $relativePath.Replace("\", "/");            
                    $ignore = $false;
                    # Is there any folders which should be ignored in this list
                    $foldersToIgnore | % {
                        if($relativePath.StartsWith($_)){
                            $ignore = $true;                
                        }
                    }
                    # Is there any of the files that should be ignored - only matching filenames
                    $filesToIgnore | % {
                        if($relativePath.EndsWith($_)){
                            $ignore = $true;                
                        }
                    }
                    
                    if(!$ignore){
                        Upload-File -localFile $theFile -relativeDestination $relativePath
                    }
                 } # End item ne null
            } # End items
         } # End if
      } # end base
    
}

# Finally execute the method to start
Start-Upload
									

Tags: , , ,

Harald S. Fianbakken on January 2nd, 2012

Ok. So you are using some sort of source control and NuGet. You’ve checked out your project to different team-members and it complains about missing references?

The type or namespace name “Ninject” could not be found ..

Well, your binaries aren’t stored in the source control (nor should they) and you won’t get these dependencies on a normal checkout.

However, there is a file (normally checked into source control, called packages.config) which stores all your dependencies in your project. We can fix your little dependency problem with a few lines of powershell.

After a clean checkout, open Nuget Package manager Console and type the following to fix your dependencies:

(This is some powershell goodies):

  • PM > cd MyProject\
  • PM> $c = Get-Content .\packages.config;
  • PM> $xml = [xml] $c;
  • PM> $packages = $xml.packages.package|select id
  • PM> $packages|%{Install-Package $_.id}

This will download and install all the packages listed in your project on your local computer (where you just checked out the project). All should be well ;) NB: If you want to install the version specific dependencies, the last two lines should be as follows:

  • PM> $packages = $xml.packages.package|select id, version
  • PM> $packages|%{Install-Package $_.id -Version $_.version}

 

Tags: , , , , , ,

Harald S. Fianbakken on December 4th, 2011

How to get the full url to a route in your ASP.NET MVC3 application? Including your port number, paths and params for your route table?

Especially if you are in a helper method or writing utilities to send emails with a request path to your deployed application this can be tricky.

I wrote the following snippet / helper method to return the full URL including port to a given route in MVC3. It is useful if you are testing, developing or in your deployed solution (if you are moving your application between servers), enjoy:)

     
public String GetUrl(string action, string controller, RouteValueDictionary dictionary)
{
            var urlHelper = new UrlHelper(((MvcHandler)HttpContext.Current.CurrentHandler).RequestContext);
            var url = urlHelper.Action("ConfirmUser", "Home", dictionary);

            var baseURI = HttpContext.Current.Request.Url.Scheme + System.Uri.SchemeDelimiter +
                         HttpContext.Current.Request.Url.Host +
                         (HttpContext.Current.Request.Url.Port != 80 ? ":" + HttpContext.Current.Request.Url.Port : "");

            return baseURI + url;
}
public void example(){
   var d=
                    new RouteValueDictionary(
                        new
                        {
                            id = member.Member_ID,
                            hash = member.Hash,
                            area=""
                        });
            var url = GetCurrentUrl("ConfirmUser", "Home", d);
}
									

Tags: , , , , ,

Harald S. Fianbakken on November 23rd, 2011

You can easily nest through levels of and lists of pages in RedDot and include whatever content you want on a page.

One of my requirements was to display all subpages of a subpage and some specific content on that level 2 subpage.

As a neat little hint, I give you the following code to nest through levels:

<!IoRangePreExecute>
<%!!Context:CurrentPage.Elements.GetElement(lst_categories).Value[Int32:0].Elements.GetElement(list_nextLevel).Value[Int32:0].Headline!!%>
<!/IoRangePreExecute>

									

Explanation

The code goes from the current page, to a list element called lst_categories, it then finds another list called lst_categories and goes to the first element, then displays it’s page title. You could get the value for whatever element you would want on the pages here. To nest all levels, you could easily write a for-loop iterating the different levels;)

Tags: , ,

Harald S. Fianbakken on November 21st, 2011

If you have multiple sites / web apps running in virtual directories with different versions (or assemblies) you would want to prevent inheriting or ignore the web.config from your root level.

You can easily to this by specifying the following in your top (root) web.config:

<location path="." inheritInChildApplications="false">
<system.web>
 ...
</system.web>
</location>
									

Tags: , , ,

Harald S. Fianbakken on November 16th, 2011

A neat little module that allows you to install/remove Windows Features without the GUI.

Just import the ServerManager and you are good to go.

E.g – Installing Powershell_ISE from Powershell;) :

Import-Module ServerManager
Add-WindowsFeature PowerShell-ISE

You can install whatever features in windows you want this way. For a full list of what they are named in powershell check this link out: TechRepublic

Tags: , , ,

Harald S. Fianbakken on November 9th, 2011

Calling a WCF service from JQuery is pretty forward.

The following function will call your WCF service and call the appropriate methods on success or on failure.

var serviceBase = "/Services/FaqService.svc"
var format = "json";

// Do not edit
var serviceUrl = serviceBase + "/"+format;

function getCategories(onSuccess, onFail) {
    specificService= serviceUrl+"/categories";
    $.ajax({
        type: "GET",
        url: specificService,
        contentType: "application/json; charset=utf-8",
        dataType: format,
        success: onSuccess, 
        error: onFail
        });
}

var someSuccessMethod = = function (transport) {
    var results = transport.GetMainCategoriesResult;
    var htmlText = "<ul>";
    for (var i = 0; i < results.length; i++) {
        htmlText += "<h3>" + results[i].Name + "</h3>";
    }
    htmlText += "</ul>";
    $("#SomeLargeText").html(htmlText);
};


var generalError = function (xhr, status) {
    alert("An error occurred: " + status);
}
									

If your WCF exposes JSON, remember to make the bindings correct to expose your data as JSON. I’ve added the following bindings in my web.config to enable all types of binding (Json, basichttp, soap etc).

<system.serviceModel>
    <!-- bindings -->
    <bindings>
      <basicHttpBinding>
        <binding name="basicHttp">
          <security mode="None">
          </security>
        </binding>
      </basicHttpBinding>
      <wsHttpBinding>
        <binding name="WsHttp">
          <security mode="None">
          </security>
        </binding>
      </wsHttpBinding>
      <webHttpBinding>
        <binding name="WebHttp">
          <security mode="None"></security>
        </binding>
        <binding name="WebjsonHttp">
          <security mode="None"></security>
        </binding>
      </webHttpBinding>
    </bindings>
    <!-- behaviors -->
    <behaviors>
      <serviceBehaviors>
        <behavior name="defaultBehavior">
          <serviceDebug includeExceptionDetailInFaults="true"/>
          <serviceMetadata httpGetEnabled="true"/>
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <clear/>
        <behavior name="jsonBehaviour">
          <webHttp defaultOutgoingResponseFormat="Json" defaultBodyStyle="Wrapped"/>
        </behavior>
        <behavior name="xmlBehaviour">
          <webHttp defaultOutgoingResponseFormat="Xml" defaultBodyStyle="Wrapped"/>
        </behavior>
      </endpointBehaviors>
    </behaviors>
<services>
      <service behaviorConfiguration="defaultBehavior" name="Tele2.FrontEnd.Main.Services.FaqService">
        <clear/>
        <endpoint address="json" binding="webHttpBinding" bindingConfiguration="WebjsonHttp" behaviorConfiguration="jsonBehaviour" name="webJSONHttpBinding" contract="Fianbakken.Main.Services.Contracts.IFaqService"/>
 <!-- Add all other bindings here --> 
      </service>
    </services>
									

The following service shows you the definition for categories which is called in the JQuery

 [ServiceContract]
    public interface IFaqService 
    {
        
        /**
         * @Return: list of all top level categories (e.g. categories) with no parent
         * */        
        
        [OperationContract]
        [WebGet(UriTemplate = "categories")]
        
        List<FaqCategory> GetMainCategories();
}

									

 

Tags: , , ,

Have you ever gotten this exception:

System.ServiceModel.FaultException`1[System.ServiceModel.ExceptionDetail]: Only parameterless constructors and initializers are supported in LINQ to Entities. (or anything similar)?

The quick workaround would be to convert the IEnumerable to a list before selecting.

The following will fail with the exception:
return _db.Categories.Select(p => new Category(p)).ToList();

The following will not fail:
return _db.Categories.ToList().Select(p => new Category(p)).ToList();

Note: Be cautious when doing this on large results and actually filter before casting it to the list (as entity framework will fetch your data).

Tags: , , , ,