Monday, November 1, 2010

Booting Windows PE from a USB Drive Walkthrough

Windows preinstallation environment (windows PE) is a bootable tool that provides a minimal set of operating system features for installation, troubleshooting, and recovery. In this post I am going to explain how you can setup a windows PE environment to boot from a USB drive in 5 simple steps:

  1. Download and install windows AIK from Microsoft
  2. Prepare WinPE image
  3. Add drivers to your WinPE image
  4. Setup USB drive to be able to boot
  5. Copy the files to USB drive

Download and install windows AIK from Microsoft

Windows AIK is a set of tools and documentation that support the configuration and deployment of Windows® operating systems. You can download WAIK from Microsoft download center http://www.microsoft.com/download (search term WAIK) and install it to your computer for free.

After WAIK installation a set of folders will be created by default under \program files\Windows AIK that contain the appropriate files and tools to create and manage WinPE images, unattended installation files, a volume activation management tool, SDKs and some sample files.

Prepare WinPE image

After installing WAIK you are ready to prepare your WinPE image. In order to do so you have to go to \program files\Windows AIK\Tools\PETools (default location) and copy your candidate WinPE image files to a temporary location. To do that you issue the command copype.cmd <x86|amd64|ia64> <temporary location> for example copype.cmd x86 c:\temp\WinPEx86 (x86 is the 32bit architecture).

As a final step you need to copy and rename the base image file c:\temp\WinPEx86\winpe.wim (based on the above example) to the ISO\Sources subdirectory of this temporary folder as boot.wim. To do this, issue the command copy c:\temp\WinPEx86\winpe.wim c:\temp\WinPEx86\ISO\sources\boot.wim. 

Add drivers to your WinPE image (optional)

In case you need to preload any drivers to your WinPE image or add optional components you have to follow some additional steps outlined below. In case you don’t you skip to the next section.

First step is to create a directory, for example c:\temp\WinPEx86\Drivers, and download your drivers in this location. Note that the drivers must be fully extracted with their .inf files exposed in order to be added to the WinPE image.

Second step is to mount the base WinPE image copied previously. To do that execute "c:\Program Files\Windows AIK\Tools\Servicing\Dism.exe" /mount-Wim /WimFile:c:\temp\WinPEx86\ISO\Sources\boot.wim /index:1 /MountDir:c:\temp\WinPEx86\Mount.

Third step is to add the downloaded drivers to the Image by executing "c:\Program Files\Windows AIK\Tools\Servicing\Dism.exe" /image:c:\temp\WinPEx86\Mount /Add-Driver /Driver:c:\temp\WinPEx86\drivers /recurse /ForceUnsigned. By including the /recurse switch you tell to the command to recurse the drivers’ subfolders for valid .inf drivers and by including the /ForceUnsigned you tell the command to ignore driver signing requirements.

Fourth step is to unmount and commit the WinPE image by executing "c:\Program Files\Windows AIK\Tools\Servicing\Dism.exe" /unmount-wim /MountDir:c:\temp\WinPEx86\Mount /commit.

Note, that you can add additional files and folders to your custom WinPE image simply by copying your files to the c:\temp\WinPEx86\Mount. These files will be loaded to the RAM drive after WinPE boot (c:\). If you don’t want these files to be loaded to the RAM Drive (consumes RAM) and be available to the USB drive instead, just copy them to a structure under c:\temp\WinPEx86\ISO folder.

Setup USB drive to be able to boot

In this step you need to use the diskpart utility (windows Vista and above O/S) to create a bootable partition to your usb drive as outlined below.

Use Diskpart to identify the disk ID of your usb drive:

diskpart
list disk


image


After you have identified your usb disk ID (based on size), you can wipe your partition information, create a new one and mark it as active.


select disk 1
clean
create partition primary
select partition 1
active
format quick fs=ntfs
assign
exit


Copy the files to USB drive



Final step is to copy the files included under your ISO subfolder to your USB drive: xcopy c:\temp\WinPEx86\ISO\*.* f:\ (where f:\ is your USB drive).



Note that you may need to alter your PC’s BIOS settings in order to be able to boot from USB drives and of course it needs to be USB boot capable.



Final Thoughts



In case you want to load drivers after WinPE boot you can use the drvload.exe command (drvload.exe inf_path).



To manipulate winPE environment you need to use the wpeutil <command> <argument> command. Most usable commands of wpeutil: EnableFirewall, DisableFirewall, Reboot, ShutDown, Initializenetwork.



Ετικέτες Technorati: ,,,

Friday, October 29, 2010

Internal or Outsourced IT Services?


“Every business must grow, evolve and remain competitive; integral part of this is technology”

For any company the right choice of an IT department, undoubtedly leads to the path of success. But what are the criteria for selecting the right team? What technology spectrum should they cover? How do I know the right choice?

It is understood that an internal IT department, is well aware of the requirements, needs and established technology of the company they supporting; but the spectrum and tremendous speed of technology evolution requires an extraordinary effort to stay up to date.

There are so many areas to cover and growth rates to keep up to, that simply makes impossible to handle. Hence one of the best ways to cover a broader spectrum is through outsourcing.

What options do I have?


It is not necessary to dismiss an internal IT department in order to meet your needs with the use of external collaborators exclusively. You can evaluate your business requirements along with your support team, in order to conclude to the areas you will delegate to external partners. You can, for example, choose to keep internally the daily technical support, user training and administration; and adopt outsourcing services for consulting, project implementation, network security and support of your ERP system.


This way you can combine the benefits of both your internal team and the expertise of your external partners. If you think you don’t want to maintain an internal IT department, there are service providers that can manage your everyday technical issues,new projects, consulting services, communication, etc.

Comparison

  Internal IT Outsourcing Combination
Pros

-Knowledge of business
-Response time

-Range of Expertise
-Flexible Resources
-Management tools
-Cost
-Expertise in project implementation
-SLA
-Applied solutions in different environments

-Knowledge of business
-Response time
-Range of Expertise
-Flexible Resources
-Management tools
-Expertise in project implementation
-SLA
-Applied solutions in different environments

Cons

-Cost of personnel maintenance
-Range of Expertise
-Expertise in project implementation
-Applied solutions in different environments
-Flexible Resources

-Response Time
-Service cost evaluation
-Service cost evaluation

 

What should I consider when choosing a partner?

During the assessment and selection of an outsourcing team you will benefit if you take into account:

  • Related projects executed in the past: It is not necessary for a service provider which has successfully executed a project regarding the implementation of an ERP system, to perform the same success with a project concerning the security of a network
  • The availability of experienced staff: It is reasonable for a company to try to cut costs. Many service providers, maintain large groups of inexperienced staff led by a single senior engineer, project manager or consultant. The problem comes when that inexperienced staff, which are not always able to assess, manage and execute a project properly, take the wrong decisions as a result of the unavailability of their manager, who may be over allocated because of the poor relationship between senior / junior staff.
  • The cost VS performance: It is obvious that a high-quality service of 700€ is advantageous compared to a low-quality service of 600€. I do not imply that expensive means better. You should take into account all factors related to quality (previous projects, experienced staff, etc.) and cost, compare your options and decide your final approach.
  • Satisfaction guarantee: Service satisfaction is somehow subjective and always end up to how happy is the customer. A service could be technically correct, but do not meet all of the business requirements. This may be a result of poor communication. But it is important that the result is not desirable and that’s where you should have a framework that defines it. In project cases, the metrics and the rules of acceptance of deliverables should always be defined in the "project definition". In cases of support contracts, along with the terms (SLA), it is good to ask for an evaluation (trial) period before sealing the deal.
  • The range of technologies covered: There are many companies that are product oriented. Sometimes this means that whatever your needs, they will try to implement their own product to your case, regardless of whether it fits or not. This may be a solution which does not cover all your requirements or is extremely advanced.
  • Availability and response time: Usually response time is ranging from 2 hours to 2 days depending on the SLA and the seriousness of a request. Timetables vary from 8 hours to 24. Support costs vary depending on response and availability.

Is your ADSL router selectively loading sites?

If you are one of those engineers, administrators, enthusiasts who encountered the situation of which a Cisco ADSL router is selectively blocking web sites, then this is the right post for you. I have seen many of my customers facing this issue and scratching their heads to understand the problem.

The issue is as following: You are browsing and using the internet normally but for some specific web sites access is impossible. Your web browser times out and site is reported as unreachable. In some cases the web site may partially loaded but if you replace the router with another (non-Cisco) you are able to access these sites as expected. When you place the Cisco router back, sites become inaccessible once more.

The fun part is that the problem is not related to Cisco as a brand.  The reason why some pages do not fully load (or not load at all) is that the router fragments IP packets greater than 1492 bytes which sent by the Source PC to the router. This fragmentation does not occur on the return path through the intermediate internet routers. When an intermediate internet router receives a packet greater than 1492 bytes, the packet is dropped, and the intermediate internet router generates and sends an Internet Control Message Protocol (ICMP) message to the web server that sent the oversized packet. The ICMP informs the web server that it sent an oversized packet and that it needs to resend the packet with a smaller MTU.

The problem occurs because many web servers block ICMP messages, which causes the server to continuously send 1500-byte packets. These packets are dropped, and as a result, the requested web site does not load. If the web server is properly configured and ICMP messages are not blocked, the server adjusts its MTU and retransmits until the page loads completely.

In order to overcome this issue the easiest thing you can do is to adjust your Cisco router with a maximum MTU size of 1452. In case this doesn’t work you can experiment with lower values up to 1360. In order to achieve this you have to change the MTU value to the internal (LAN) interface(s) of your Cisco router as follows:

interface FastEthernet0/0 (or whatever your interface is vlan1, ethernet0, etc)

ip adjust-mss 1452

 

What is this RemoteFX everybody is talking about?

It is actually an add-on for RDP that enables the delivery of a full Windows user experience to a range of client devices including rich clients, thin clients, and ultrathin clients. It delivers a rich user experience for Virtual Desktop Infrastructure (VDI) by enabling host side rendering, GPU virtualization, Intelligent Screen Capture, Encoding, Decoding, and USB redirection.

RemoteFX enables host side rendering which allows graphics to be rendered on the host device instead of on the client which allows the applications to run at full speed by taking advantage of the GPU and CPU of host computer since all graphic types are rendered on the host computer, compressed as bitmap images and send to client computer.

RemoteFX is also capable of GPU virtualization by exposing a virtual graphic device to a virtual machine. Using a WDDM driver with the virtual desktop, allows multiple virtual desktops to share a single GPU on a Hyper-V server.

In order to take care of bandwidth limitations RemoteFX uses Intelligent Screen Capture, a technology which constantly detects network capability between client and host and adjusts frame-rate according to available bandwidth. Intelligent Screen Capture is designed to send more frames to ensure a good user experience.

RemoteFX encoder and decoder allows encoding on the processor, on the GPU, or on dedicated hardware on the host computer and decoding on the client.

Finally the USB redirection support allows many devices to be redirected to a Remote Desktop Virtualization Host server at the USB level. No device drivers are required on the client computer and universal interface is provided that works with any USB device on any platform where RemoteFX USB Redirection is supported. This solution redirects many types of devices, including audio devices, storage devices, human interface devices, all-in-one printers, and scanners.

How to configure RemoteFX?

Deploying RemoteFX for Virtual Desktop Pools Step-by-Step Guide

Deploying Microsoft RemoteFX for Personal Virtual Desktops Step-by-Step Guide

Deploying Microsoft RemoteFX on a Remote Desktop Session Host Server Step-by-Step Guide

Source: Microsoft.com
Ετικέτες Technorati: ,,

Tuesday, November 10, 2009

9 Simple Network Security Rules

What about it? You can just put a firewall and here you are! Completely Safe!

A few years ago maybe... But in nowadays the things are little bit different. Instant messaging, P2P networks, in-house web and mail services, streaming, Trojans, worms, and many more, can open temporary or even permanent "doors" inside your network; even if you have a firewall installed. You should think your network security as a whole! You cannot consider your network safe if:

  • everybody has administrative rights
  • you have an expired antivirus
  • you have not a perimeter security device
  • you have not reduced your "attack surface"
  • you have not design your "defense in depth" strategy appropriately
  • you use weak passwords
  • you do not use web filters
  • you do not patch your applications and O/S
  • you have not trained your users

Rule #1: Administrative Permissions Is Your Enemy

The first thing I do when I am hired by a company to secure their network, is to limit administrative permissions from users' workstations. These workstations are vulnerable when executing processes, like Internet explorer, with administrative rights. But you have to take care of two things first:

  • Users' reactions! Most users won't like that kind of restriction. I always explain why I am proceeding to such action, to avoid inconvenience. I am also committed that I will take care of any special requests that may arise.
  • Proprietary software side effects. You have to make sure that everything is working as expected.

Rule #2: Weak Passwords, Just Make You Weak

Weak passwords is a common practice by many companies. Most users use a simple 4-8 character password; like their birthday, a simple word, etc. From the other hand, if you enforce long passwords with complexity, you will probably end up with stickers of hand written passwords on each of your users' monitor. If you have the budget try to introduce smartcards, biometrics or OTP tokens. If you can't, train your users to use passwords that comprise of long phrases like "I like to go for shopping 5 times a week!". These are strong and easy to remember.

Rule #3: Defense!

You have to reduce your attack surface:

  • Uninstall unnecessary software
  • Disable unnecessary services
  • Limit the accounts that are domain administrators
  • Configure local firewalls to servers
  • Configure local Intrusion Prevention Systems to servers (most times it is part of a firewall)
  • Take care of expired antivirus and antispyware systems
  • Regularly patch your applications and O/S

Rule #4: Another Brick On The Wall

Choose your security device wisely. Although Cisco and MS ISA Server are safe choices for large organizations; For SMBs may not be. -And why is that? -Budget! If you decide to install an ISA server, for example, you will get an excellent stateful firewall, with excellent proxy capabilities, no smart web categorization, no antivirus, no antispyware, limited IPS. You have to add web filtering, antivirus, antispyware, IPS with extra cost. If you can, then it is an excellent choice with unique capabilities, if you can't, it would be wise to purchase an all-in-one solution even if it is not state of the art.

Rule #5: Limit The Noise

Try to reduce the dropped packets "noise" from your firewall logs by setting simple filtering rules to you Internet routers:

  • Drop private networks, broadcasts and multicasts.
  • Setup NAT and/or PAT to your public interface

Rule #6: Test, Test and Test

  • Purchase a software and run security audits to your servers and workstations
  • Purchase a software and try to penetrate your firewalls from the inside and from the outside
  • Check the logs of your perimeter security devices. Is there anything unusual?
  • Check the logs of your local firewalls. Is there anything unusual?
  • Compare perimeter and local firewalls' logs. Is something passing through the perimeter device and logged to the local firewall?

Rule #7 :Train Your Users

Simple rules like don't open "strange" email messages and don't press yes to any warnings that may appear to your screen can make the difference.

Rule #8: Don’t forget to backup

It is wise to backup the latest configuration state of your devices and your data regularly. If your firewall crashes it would be much easier to restore a configuration file than to set it up from scratch. Also if a SCSI controller crashes on a SQL server or a user accidentally deletes a shared directory it would be to your benefit if you had backed up your files and databases recently.

Rule #9: Check the latest security best practices

Update your security strategy regularly by checking the latest best practices. You can find appropriate info at www.cert.org, www.sans.org, www.cisecurity.org, www.w3.org/security,

Thursday, September 24, 2009

The MOSS Search Saga: Modifying the advanced search page

In a previous post of mine I explained how to create managed properties and modify the search results page for a custom Protocol application. In this post I am going to continue from my previous example by modifying the advanced search tab.

The idea is to modify the search page in order to include some of my managed properties in the search query logic, add the “contains” and “does not contain” equation in my search expressions and limit the language query options to English an Greek only.

  • I navigate to the advanced search page and I go into edit page mode
    image
  • I select the edit menu of the Advanced Search Box webpart and the Modify Shared Web part option
    image
  • In the Advanced Search Box –> Properties –> I pres the … icon in the Properties field
    image
  • A new window appears with the XML format of the advanced search properties

    <root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance%22>
    <Option Name="AllowOpContains" Value="False"/>
    <LangDefs>
    <LangDef DisplayName="Arabic" LangID="1"/>
    <LangDef DisplayName="Bengali" LangID="69"/>
    <LangDef DisplayName="Bulgarian" LangID="2"/>
    <LangDef DisplayName="Catalan" LangID="3"/>
    <LangDef DisplayName="Chinese" LangID="4"/>
    <LangDef DisplayName="Croatian/Serbian" LangID="26"/>
    <LangDef DisplayName="Czech" LangID="5"/>
    <LangDef DisplayName="Danish" LangID="6"/>
    <LangDef DisplayName="Dutch" LangID="19"/>
    <LangDef DisplayName="Finnish" LangID="11"/>
    <LangDef DisplayName="French" LangID="12"/>
    <LangDef DisplayName="German" LangID="7"/>
    <LangDef DisplayName="Greek" LangID="8"/>
    <LangDef DisplayName="Gujrati" LangID="71"/>
    <LangDef DisplayName="Hebrew" LangID="13"/>
    <LangDef DisplayName="Hindi" LangID="57"/>
    <LangDef DisplayName="Hungarian" LangID="14"/>
    <LangDef DisplayName="Icelandic" LangID="15"/>
    <LangDef DisplayName="Indonesian" LangID="33"/>
    <LangDef DisplayName="Italian" LangID="16"/>
    <LangDef DisplayName="Japanese" LangID="17"/>
    <LangDef DisplayName="Kannada" LangID="75"/>
    <LangDef DisplayName="Korean" LangID="18"/>
    <LangDef DisplayName="Latvian" LangID="38"/>
    <LangDef DisplayName="Lithuanian" LangID="39"/>
    <LangDef DisplayName="Malay" LangID="62"/>
    <LangDef DisplayName="Malayalam" LangID="76"/>
    <LangDef DisplayName="Marathi" LangID="78"/>
    <LangDef DisplayName="Norwegian" LangID="20"/>
    <LangDef DisplayName="Polish" LangID="21"/>
    <LangDef DisplayName="Portugese" LangID="22"/>
    <LangDef DisplayName="Punjabi" LangID="70"/>
    <LangDef DisplayName="Romanian" LangID="24"/>
    <LangDef DisplayName="Russian" LangID="25"/>
    <LangDef DisplayName="Slovak" LangID="27"/>
    <LangDef DisplayName="Slovenian" LangID="36"/>
    <LangDef DisplayName="Spanish" LangID="10"/>
    <LangDef DisplayName="Swedish" LangID="29"/>
    <LangDef DisplayName="Tamil" LangID="73"/>
    <LangDef DisplayName="Telugu" LangID="74"/>
    <LangDef DisplayName="Thai" LangID="30"/>
    <LangDef DisplayName="Turkish" LangID="31"/>
    <LangDef DisplayName="Ukrainian" LangID="34"/>
    <LangDef DisplayName="Urdu" LangID="32"/>
    <LangDef DisplayName="Vietnamese" LangID="42"/>
    </LangDefs>
    <Languages>
    <Language LangRef="12"/>
    <Language LangRef="7"/>
    <Language LangRef="17"/>
    <Language LangRef="10"/>
    </Languages>
    <PropertyDefs>
    <PropertyDef Name="Path" DataType="text" DisplayName="URL"/>
    <PropertyDef Name="Size" DataType="integer" DisplayName="Size"/>
    <PropertyDef Name="Write" DataType="datetime" DisplayName="Last Modified Date"/>
    <PropertyDef Name="FileName" DataType="text" DisplayName="Name"/>
    <PropertyDef Name="Description" DataType="text" DisplayName="Description"/>
    <PropertyDef Name="Title" DataType="text" DisplayName="Title"/>
    <PropertyDef Name="Author" DataType="text" DisplayName="Author"/>
    <PropertyDef Name="DocSubject" DataType="text" DisplayName="Subject"/>
    <PropertyDef Name="DocKeywords" DataType="text" DisplayName="Keywords"/>
    <PropertyDef Name="DocComments" DataType="text" DisplayName="Comments"/>
    <PropertyDef Name="Manager" DataType="text" DisplayName="Manager"/>
    <PropertyDef Name="Company" DataType="text" DisplayName="Company"/>
    <PropertyDef Name="Created" DataType="datetime" DisplayName="Created Date"/>
    <PropertyDef Name="CreatedBy" DataType="text" DisplayName="Created By"/>
    <PropertyDef Name="ModifiedBy" DataType="text" DisplayName="Last Modified By"/>
    </PropertyDefs>
    <ResultTypes>
    <ResultType DisplayName="All Results" Name="default">
    <Query/>
    <PropertyRef Name="Author"/>
    <PropertyRef Name="Description"/>
    <PropertyRef Name="FileName"/>
    <PropertyRef Name="Size"/>
    <PropertyRef Name="Path"/>
    <PropertyRef Name="Created"/>
    <PropertyRef Name="Write"/>
    <PropertyRef Name="CreatedBy"/>
    <PropertyRef Name="ModifiedBy"/>
    </ResultType>
    <ResultType DisplayName="Documents" Name="documents">
    <Query>IsDocument=1</Query>
    <PropertyRef Name="Author"/>
    <PropertyRef Name="DocComments"/>
    <PropertyRef Name="Description"/>
    <PropertyRef Name="DocKeywords"/>
    <PropertyRef Name="FileName"/>
    <PropertyRef Name="Size"/>
    <PropertyRef Name="DocSubject"/>
    <PropertyRef Name="Path"/>
    <PropertyRef Name="Created"/>
    <PropertyRef Name="Write"/>
    <PropertyRef Name="CreatedBy"/>
    <PropertyRef Name="ModifiedBy"/>
    <PropertyRef Name="Title"/>
    <PropertyRef Name="Manager"/>
    <PropertyRef Name="Company"/>
    </ResultType>
    <ResultType DisplayName="Word Documents" Name="worddocuments">
    <Query>FileExtension='doc' Or FileExtension='docx' Or FileExtension='dot'</Query>
    <PropertyRef Name="Author"/>
    <PropertyRef Name="DocComments"/>
    <PropertyRef Name="Description"/>
    <PropertyRef Name="DocKeywords"/>
    <PropertyRef Name="FileName"/>
    <PropertyRef Name="Size"/>
    <PropertyRef Name="DocSubject"/>
    <PropertyRef Name="Path"/>
    <PropertyRef Name="Created"/>
    <PropertyRef Name="Write"/>
    <PropertyRef Name="CreatedBy"/>
    <PropertyRef Name="ModifiedBy"/>
    <PropertyRef Name="Title"/>
    <PropertyRef Name="Manager"/>
    <PropertyRef Name="Company"/>
    </ResultType>
    <ResultType DisplayName="Excel Documents" Name="exceldocuments">
    <Query>FileExtension='xls' Or FileExtension='xlsx' Or FileExtension='xlt'</Query>
    <PropertyRef Name="Author"/>
    <PropertyRef Name="DocComments"/>
    <PropertyRef Name="Description"/>
    <PropertyRef Name="DocKeywords"/>
    <PropertyRef Name="FileName"/>
    <PropertyRef Name="Size"/>
    <PropertyRef Name="DocSubject"/>
    <PropertyRef Name="Path"/>
    <PropertyRef Name="Created"/>
    <PropertyRef Name="Write"/>
    <PropertyRef Name="CreatedBy"/>
    <PropertyRef Name="ModifiedBy"/>
    <PropertyRef Name="Title"/>
    <PropertyRef Name="Manager"/>
    <PropertyRef Name="Company"/>
    </ResultType>
    <ResultType DisplayName="Presentations" Name="presentations">
    <Query>FileExtension='ppt'</Query>
    <PropertyRef Name="Author"/>
    <PropertyRef Name="DocComments"/>
    <PropertyRef Name="Description"/>
    <PropertyRef Name="DocKeywords"/>
    <PropertyRef Name="FileName"/>
    <PropertyRef Name="Size"/>
    <PropertyRef Name="DocSubject"/>
    <PropertyRef Name="Path"/>
    <PropertyRef Name="Created"/>
    <PropertyRef Name="Write"/>
    <PropertyRef Name="CreatedBy"/>
    <PropertyRef Name="ModifiedBy"/>
    <PropertyRef Name="Title"/>
    <PropertyRef Name="Manager"/>
    <PropertyRef Name="Company"/>
    </ResultType>
    </ResultTypes>
    </root>

Let’s explore the XML in order to see how we can manipulate the advanced search box query properties:

  • To include the “contains” and “does not contain” equation in my search expressions I just need to edit the Option AllowOpContains (Red Text) from False to True.
  • To leave only the Greek and English language option in my languages search query, I have to edit the <Language LangRef=”Number”> tag (Orange Text) with the appropriate language definition number (Grey Text).
  • I check the language definitions list for the Greek language and I notice that the Greek definition is equal to “8” (Grey Text). I Remove all <Language LangRef=”Number”> tags and I leave only one; the one with the Greek language Definition <Language LangRef=”8”> (Orange Text).
  • To include my managed properties in search terms I have to add a property definition for my managed property (Blue Text) and a Property Reference (Green Text) for the appropriate definition to appear in the properties dropdown list.
  • To create a property definition for my ProtOurPID managed property, I have to include a <PropertyDef Name=”ProtOurPID” DataType=”Text” DisplayName=”Our PID”/> tag (Blue Text) where Name=”My managed property name”, DataType=”Data type (Text, DateTime, etc)”, DisplayName=”The appearance in the pick property drop down menu

    <PropertyDef Name="ProtOurPID" DataType="text" DisplayName="Our PID"/>
    <PropertyDef Name="ProtSubject" DataType="text" DisplayName="Subject"/>
    <PropertyDef Name="ProtINOUT" DataType="text" DisplayName="IN/OUT"/>
    <PropertyDef Name="ProtDocumentDate" DataType="datetime" DisplayName="Document Date"/>
    <PropertyDef Name="ProtINTOriginDestination" DataType="text" DisplayName="Internal Origin/Destination"/>
    <PropertyDef Name="ProtEXTOriginDestination" DataType="text" DisplayName="External Origin/Destination"/>
    <PropertyDef Name="ProtCommentsDescriptions" DataType="text" DisplayName="Protocol Comments / Description"/>
    <PropertyDef Name="ProtTheirPID" DataType="text" DisplayName="Their PID"/>

  • Finally, I need to be able to query my custom managed properties. In order to do so, I have to create a Property Reference for my Property Definitions I created earlier. I have the option to create groupings of Property References called Result Types. Result Types can have their own groupings of Property References and filtering queries. For example, to create a Result Type for my Protocol Lists I can add the following markup just before the </ResultTypes> closing tag:

    <ResultType DisplayName="Protocols" Name="Protocol">
    <Query>IsDocument=0</Query>
    <PropertyRef Name="ProtOurPID"/>
    <PropertyRef Name="ProtSubject"/>
    <PropertyRef Name="ProtINOUT"/>
    <PropertyRef Name="ProtDocumentDate"/>
    <PropertyRef Name="ProtINTOriginDestination"/>
    <PropertyRef Name="ProtEXTOriginDestination"/>
    <PropertyRef Name="ProtTheirPID"/>
    </ResultType>

  • This result type will query the results that are not documents “<Query>IsDocument=0</Query>” and will allow you to query only the grouping of the managed properties referenced in that particular result type.

You can always create more complex queries by adding OR and AND statements. Like:

<Query>FileExtension='xls' Or FileExtension='xlsx' Or FileExtension='xlt'</Query>

Friday, August 21, 2009

The MOSS Search Saga: Modifying The Search Results Page

The customization of the search experience in MOSS is crucial in many situations. You may need to add additional metadata to your display results, to modify the search result page layout or to add additional metadata properties to your advanced search page. In the paragraphs below I am going to demonstrate a simple scenario of MOSS search experience customization.

In the first part of this example I am going to create a tabular layout of my search results page for an e-protocol SharePoint list. I am going to demonstrate the way to add additional metadata to the search results page, to modify the layout using SharePoint Designer and in the second part to modify the advanced search page to include more options to query.

Before I start customizing my search results page I need to populate some custom columns, I created to my e-protocol SharePoint list. Each time SharePoint crawls the farm to create indexed content, it adds any custom column (metadata property) it finds in Lists, Document Libraries and Sites, to its metadata properties database. But for those properties to become manageable, MOSS administrator needs to create a “managed property” record for each of the metadata he needs to manage. Notice that each “managed property” can map to one or more metadata properties. For example, if I want to create a managed property for the ProtocolID metadata, I would create a single map for this property. This could become available to my search results page and advanced search queries. Now consider the following scenario: I want to create a single managed property to query and display all kinds of calling number information across my contacts lists. I should create a single managed property which maps to multiple metadata properties: mobile phone, home phone, company phone, etc.

I am going to create seven (7) managed properties for my Protocol Application List. In order to create these managed properties I need to navigate to the Search Administration Page of my SSP:

  • From there I navigate to the metadata properties in the side menu and I select new managed property.
  • I type an appropriate name for my new managed property (ex ProtID)
  • I select the appropriate type of this property (ex Text)
    image
  • I add the appropriate mapping by selecting a crawled metadata property to map to this managed property (ex ows_PID)
    image
  • Press the OK button

At this point I repeat the same procedure for the next six (6) managed properties I want to create:
image

From that point, I want to modify my search results page. In my search results page I want to display, in a tabular format, the ProtPID, ProtSubject, ProtINOUT, ProtDocumentDate, ProtNTOriginDestination and ProtEXTOriginDestination properties I have created in the previous steps. SharePoint server/services return the search results in an XML format. The visual presentation of this XML format is done by XSLT and CSS. So, in order to manipulate the visual representation of those results I have to extract their raw XML form.

To extract the raw XML form of my search results:

  • I navigate to my search center web site
  • I submit a search term in the search box (ex Test)
  • In the search results page I navigate to the site actions menu and I select the edit page menu item
    image
  • I select the edit menu of the Search Core Results WebPart and the Modify Shared Web Part option
    image
  • In the Search Core Results –> Data View Properties –> I press XSL Editor..
    image
  • I replace all code with the following:
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform%22 >
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />
    <xsl:template match="/">
    <xmp><xsl:copy-of select="*"/></xmp>
    </xsl:template>
    </xsl:stylesheet>
  • I press the apply Button

Notice the changes to the core results. A raw XML format of the results is displayed. But wait a minute… Where are the managed properties I created earlier? The answer is nowhere. I need to tell the WebPart to add those properties to the XML results:

  • In the Results Query Options of the Search Core Results properties, press the … icon in the Selected Columns option
    image
  • Notice the format and the changes I made to the bottom of the XML:
    <root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance%22>
    <Columns>
    <Column Name="WorkId"/>
    <Column Name="Rank"/><Column Name="Title"/>
    <Column Name="Author"/>
    <Column Name="Size"/>
    <Column Name="Path"/>
    <Column Name="Description"/>
    <Column Name="Write"/><Column Name="SiteName"/>
    <Column Name="CollapsingStatus"/>
    <Column Name="HitHighlightedSummary"/>
    <Column Name="HitHighlightedProperties"/>
    <Column Name="ContentClass"/>
    <Column Name="IsDocument"/>
    <Column Name="PictureThumbnailURL"/>
    <Column Name="ProtOurPID"/>
    <Column Name="ProtSubject"/>
    <Column Name="ProtINOUT"/>
    <Column Name="ProtDocumentDate"/>
    <Column Name="ProtINTOriginDestination"/>
    <Column Name="ProtEXTOriginDestination"/>

    </Columns>
    </root>
  • Before the closing Columns statement </Columns> I added 6 of my managed properties in the form of: <Column Name=”MyManagedProperty” />
  • Press the OK Button

Now, I have my Raw XML results with my managed properties included. To manipulate their layout using Sharepoint Designer, I have to save those results as an XML file and import it as a data source:

  • I copy the raw XML format of the search results (from <All_Results> to </All_results>) into notepad and I save the file as RawXMLResults.xml somewhere in my local drive
  • I open my SharePoint site and I temporarily save the RawXMLResults.xml to one of my document libraries
  • In SharePoint Designer I create a new ASPX page
    image
  • In the Data View menu I select the Insert Data View Option…
    image
  • In the Data Source Library (Right Pane in SharePoint Designer) I expand the XML Files, and I select the Add an XML File… hyperlink:
    image
  • In the new window I select the Source tab and I browse for the RawXMLResults.xml file I saved in a previous step to one of my document libraries
  • After pressing OK the new XML file appears in the list of my XML Datasources
  • By selecting the file, a drop down menu appears. I click the Show Data Option
    image
  • Having selected the data source webpart in my ASPX Page
    image
  • I select the columns I want to add to my layout and from the Insert Selected Fields as… menu, I select the Multiple Item View
    image
  • Note that the order I selected the columns, is the order that is displayed in my table
  • After making the appropriate modifications to my layout, I need to copy the XSLT code and paste it back to my Search Core Results WebPart. So, I copy the code from the <xsl:stylesheet … to the </xsl:stylesheet> element.
    image
  • My final step is to paste the code to the XSL Editor… in my Search Core Results WebPart properties to see the effect.
    image

Personally I prefer to manipulate XSLT by using external file references instead of pasting the code directly to the WebPart. If you want to achieve the same, do the following:

  • Create a document library to host your XSL files (ex Transformations)
  • Instead of pasting the code from Sharepoint Designer directly to the WebPart, paste it to notepad and save the file as something.xsl
  • Upload something.xsl to your document library
  • In the XSL Editor… of the Search Core Results WebPart Reference to the file by using the sample code below:

    <?xml version="1.0" encoding="ISO-8859-1"?>
    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform%22>

    <xsl:import href="/Transformations/something.xsl"/>

    <xsl:template match="/">
    <xsl:apply-imports/>
    </xsl:template>

    </xsl:stylesheet>

A last thing. In order to be able to sort results by relevance / by date and to display the predefined text in case there are no results to return back, you have to copy the following code from the shipped results XSLT to your custom one:

<xsl:param name="ResultsBy" />
<xsl:param name="ViewByUrl" />
<xsl:param name="ViewByValue" />
<xsl:param name="IsNoKeyword" />
<xsl:param name="IsFixedQuery" />
<xsl:param name="ShowActionLinks" />
<xsl:param name="MoreResultsText" />
<xsl:param name="MoreResultsLink" />
<xsl:param name="CollapsingStatusLink" />
<xsl:param name="CollapseDuplicatesText" />
<xsl:param name="AlertMeLink" />
<xsl:param name="AlertMeText" />
<xsl:param name="SrchRSSText" />
<xsl:param name="SrchRSSLink" />
<xsl:param name="ShowMessage" />
<xsl:param name="IsThisListScope" />
<xsl:param name="DisplayDiscoveredDefinition" select="True" />
<xsl:param name="NoFixedQuery" />
<xsl:param name="NoKeyword" />
<xsl:param name="NoResults" />
<xsl:param name="NoResults1" />
<xsl:param name="NoResults2" />
<xsl:param name="NoResults3" />
<xsl:param name="NoResults4" />
<xsl:param name="DefinitionIntro" />

<!-- When there is keywory to issue the search -->
<xsl:template name="dvt_1.noKeyword">
<span class="srch-description">
<xsl:choose>
<xsl:when test="$IsFixedQuery">
<xsl:value-of select="$NoFixedQuery" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$NoKeyword" />
</xsl:otherwise>
</xsl:choose>
</span>
</xsl:template>

<!-- When empty result set is returned from search -->
<xsl:template name="dvt_1.empty">
<div class="srch-sort">
<xsl:if test="$AlertMeLink and $ShowActionLinks">
<span class="srch-alertme" > <a href ="{$AlertMeLink}" id="CSR_AM1" title="{$AlertMeText}"><img style="vertical-align: middle;" src="/_layouts/images/bell.gif" alt="" border="0"/><xsl:text disable-output-escaping="yes">&amp;nbsp;</xsl:text><xsl:value-of select="$AlertMeText" /></a>
</span>
</xsl:if>

<xsl:if test="string-length($SrchRSSLink) &gt; 0 and $ShowActionLinks">
<xsl:if test="$AlertMeLink">

</xsl:if>
<a type="application/rss+xml" href ="{$SrchRSSLink}" title="{$SrchRSSText}" id="SRCHRSSL"><img style="vertical-align: middle;" border="0" src="/_layouts/images/rss.gif" alt=""/><xsl:text disable-output-escaping="yes">&amp;nbsp;</xsl:text><xsl:value-of select="$SrchRSSText"/></a>
</xsl:if>
</div>
<br/> <br/>

<span class="srch-description" id="CSR_NO_RESULTS">
<xsl:value-of select="$NoResults" />

<ol>
<li><xsl:value-of select="$NoResults1" /></li>
<li><xsl:value-of select="$NoResults2" /></li>
<li><xsl:value-of select="$NoResults3" /></li>
<li><xsl:value-of select="$NoResults4" /></li>
</ol>
</span>
</xsl:template>

<!-- Main body template. Sets the Results view (Relevance or date) options -->
<xsl:template name="dvt_1.body">
<div class="srch-results">
<xsl:if test="$ShowActionLinks">
<div class="srch-sort"> <xsl:value-of select="$ResultsBy" />
<xsl:if test="$ViewByUrl">

<a href ="{$ViewByUrl}" id="CSR_RV" title="{$ViewByValue}">
<xsl:value-of select="$ViewByValue" />
</a>
</xsl:if>
<xsl:if test="$AlertMeLink">

<span class="srch-alertme" > <a href ="{$AlertMeLink}" id="CSR_AM2" title="{$AlertMeText}"><img style="vertical-align: middle;" src="/_layouts/images/bell.gif" alt="" border="0"/><xsl:text disable-output-escaping="yes">&amp;nbsp;</xsl:text><xsl:value-of select="$AlertMeText" /></a>
</span>
</xsl:if>
<xsl:if test="string-length($SrchRSSLink) &gt; 0">

<a type="application/rss+xml" href ="{$SrchRSSLink}" title="{$SrchRSSText}" id="SRCHRSSL"><img style="vertical-align: middle;" border="0" src="/_layouts/images/rss.gif" alt=""/><xsl:text disable-output-escaping="yes">&amp;nbsp;</xsl:text><xsl:value-of select="$SrchRSSText"/></a>
</xsl:if>
</div>
<br /><br />
</xsl:if>
<xsl:apply-templates />

</div>
<xsl:call-template name="DisplayMoreResultsAnchor" />
</xsl:template>

<!—Your Results Template Goes Here –>

<!—Your Results Template Goes Here –>

<!-- The "view more results" for fixed query -->
<xsl:template name="DisplayMoreResultsAnchor">
<xsl:if test="$MoreResultsLink">
<a href="{$MoreResultsLink}" id="CSR_MRL">
<xsl:value-of select="$MoreResultsText"/>
</a>
</xsl:if>
</xsl:template>

<xsl:template match="All_Results/DiscoveredDefinitions">
<xsl:variable name="FoundIn" select="DDFoundIn" />
<xsl:variable name="DDSearchTerm" select="DDSearchTerm" />
<xsl:if test="$DisplayDiscoveredDefinition = 'True' and string-length($DDSearchTerm) &gt; 0">
<script language="javascript">
function ToggleDefinitionSelection()
{
var selection = document.getElementById("definitionSelection");
if (selection.style.display == "none")
{
selection.style.display = "inline";
}
else
{
selection.style.display = "none";
}
}
</script>
<div>
<a href="#" onclick="ToggleDefinitionSelection(); return false;">
<xsl:value-of select="$DefinitionIntro" /><b><xsl:value-of select="$DDSearchTerm"/></b></a>
<div id="definitionSelection" class="srch-Description" style="display:none;">
<xsl:for-each select="DDefinitions/DDefinition">
<br/>
<xsl:variable name="DDUrl" select="DDUrl" />
<xsl:value-of select="DDStart"/>
<b>
<xsl:value-of select="DDBold"/>
</b>
<xsl:value-of select="DDEnd"/>
<br/>
<xsl:value-of select="$FoundIn"/>
<a href="{$DDUrl}">
<xsl:value-of select="DDTitle"/>
</a>
</xsl:for-each>
</div>
</div>
</xsl:if>
</xsl:template>

<!-- XSL transformation starts here -->
<xsl:template match="/">
<xsl:if test="$AlertMeLink">
<input type="hidden" name="P_Query" />
<input type="hidden" name="P_LastNotificationTime" />
</xsl:if>
<xsl:choose>
<xsl:when test="$IsNoKeyword = 'True'" >
<xsl:call-template name="dvt_1.noKeyword" />
</xsl:when>
<xsl:when test="$ShowMessage = 'True'">
<xsl:call-template name="dvt_1.empty" />
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="dvt_1.body"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>