Removing Document Icon Definitions in Sharepoint 2007

In my last post, I talked about adding a document icon definition to the DOCICON.XML file.  This article is a companion article that will disucss how to remove a specific definition from the file.  Since it is possible to zero in on the necessary definition using XPath definitions, this script will be a lot shorter.

We will start off with a lot of the same code as in the first script.  The Sharepoint assemblies will be loaded, the file path will be generated, and we will load the XML Document into memory with Powershell.

Write-Debug -Message "Loading the Sharepoint Utilities Assembly"
 [void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Utilities")
 
 $xmlFilename = [Microsoft.SharePoint.Utilities.SPUtility]::GetGenericSetupPath("TEMPLATE\XML\DOCICON.XML").Replace(":","$").Insert(0,"<a href="file://\\$ComputerName\">\\$ComputerName\</a>")
 Write-Debug -Message "Getting `$xmlFilename - $xmlFileName"
 
 Write-Debug -Message "Loading the content from the xml file"
 $iconFile = [xml](get-content $xmlFilename)

The next action taken will be to create a $delNode variable.  Since the XMLNode object does not have a constructor, I am using the CloneNode method of the XMLDocument class to create a generic one.  It is basically just getting the top-level node of the document to instantiate it. 

$delNode = $iconFile.CloneNode($false)
 if ($extension){
  Write-Debug -Message "Looking for extensions, so setting the `$delNode variable to the extension, if found."
  $delNode = $iconFile.SelectSingleNode("//Mapping[@Key='$extension']")
  
 }
 
 if ($prodId){
  Write-Debug -Message "Looking for the progid, so detting the `$delNode variable to the progid, if found."
  $delNode = $iconFile.SelectSingleNode("//Mapping[@Key='$progId']")
  
 }

It is possible to act on the SelectSingleNode method inside each “if” statement.  However, to reduce the redundant code I chose to create a $delNode variable outside the “if” statements, and then delete the targeted node if one is found.

However, since I do have information in the $delNode variable from where I instantiated it, I need to test to make sure that it is actually something I want to delete.

if ($delNode -ne $iconFile.CloneNode($false){
  Write-Debug -Message "`$delNode value has changed, meaning that it found one of the targets.  Delete the node and save."
  $delNode.ParentNode.RemoveChild($delNode)
  $iconFile.Save($xmlFilename)
 }

Since we know what the $delNode variable should contain, if that value changes, then the code inside the “if” block will run.  Inside the block, we get the ParentNode property of the $delNode variable and use the RemoveChild() method of that parent node.  The RemoveChild method takes the argument of the $delNode variable to tell it which node to remove from that parent.  Finally, the file is saved back to the original location.

Since we are still using the CmdletBinding properties for an Advanced Function, we can add machines using the pipeline or by passing a named property to the script.  Here is the complete script source file.


[CmdletBinding()]
PARAM(
 [parameter(ValueFromPipeline=$true)]
 [string[]]
  $computername=$env:computername,
 [string]
  $extension,
 [string]
  $progId
 )

BEGIN {
 Write-Debug -Message "Begin Block..."
}

PROCESS {
 If ((!$extension) -AND (!$progId)) {
  Write-Host "You must provide either an extension or a Program ID." -fore yellow
  Write-Debug -Message "Neither the extension nor the progID wer provided...Must have one."
  Exit
 }
 
 If (($progId) -AND ($extension)){
  Write-Host "You cannot use an extension and a Program ID at the same time." -fore yellow
  Write-Debug -Message "Both extension and progid were provided...Can only have one."
  Exit
 }

 Write-Debug -Message "Loading the Sharepoint Utilities Assembly"
 [void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Utilities")
 
 $xmlFilename = [Microsoft.SharePoint.Utilities.SPUtility]::GetGenericSetupPath("TEMPLATE\XML\DOCICON.XML").Replace(":","$").Insert(0,"<a href="file://\\$ComputerName\">\\$ComputerName\</a>")
 Write-Debug -Message "Getting `$xmlFilename - $xmlFileName"
 
 Write-Debug -Message "Loading the content from the xml file"
 $iconFile = [xml](get-content $xmlFilename)
 Write-Debug -Message "Creating a `$delNode var to hold what we are looking for."
 $delNode = $iconFile.CloneNode($false)
 if ($extension){
  Write-Debug -Message "Looking for extensions, so setting the `$delNode variable to the extension, if found."
  $delNode = $iconFile.SelectSingleNode("//Mapping[@Key='$extension']")
  
 }
 
 if ($prodId){
  Write-Debug -Message "Looking for the progid, so detting the `$delNode variable to the progid, if found."
  $delNode = $iconFile.SelectSingleNode("//Mapping[@Key='$progId']")
  
 }
 
 if ($delNode -ne $iconFile.CloneNode($false){
  Write-Debug -Message "`$delNode value has changed, meaning that it found one of the targets.  Delete the node and save."
  $delNode.ParentNode.RemoveChild($delNode)
  $iconFile.Save($xmlFilename)
 }
}

END {
 Write-Debug -Message "End Block"
}

Please feel free to post a comment about my article.  While the methods above are things I have found to work, my ideas are by no means the only way to do something.  I would love to hear of other ways that you have been able to use this or if you have an easier way to implement the code.

Advertisements
This entry was posted in Sharepoint 2007, Uncategorized, XML and tagged , , , , , . Bookmark the permalink.