Friday, May 15, 2009

Remotely execute GPUPDATE via PowerShell with Invoke-GPUpdate function

I was looking around a few days brushing up on the new cmdlets in PowerShell v2. Today the need arose (again) where I wanted to remotely force a GPUPDATE on several computers (for updating computer components of a GPO). Of course I wanted to accomplish this with PowerShell. The first thing that came to mind was the “Start-Process” cmdlet. Unfortunately a quick look at the help for Start-Process showed no option for connecting to a remote computer. The next thing that came to mind was WMI, specifically the new Invoke-WMIMethod (with a name like “Invoke-WMIMethod”, how could it go wrong). After a quick read of the help for Invoke-WMIMethod I was off and running. A few one liner tests from the console and then I ended up with the function below.

Invoke-GPUpdate takes one parameter called “ComputerName”, which as you can guess by the name provides the name (or IP) of the computer you want to run gpupdate on. The first thing the function does is attempt to connect to WMI on the target computer (Get-WMIObject). If it fails to connect to WMI it throws an error (“Unable to connect to <computername>”). If it successfully connects to WMI then it uses the version information from win32_operatingsystem to determine how to update group policy. If the OS version is equal to 5.1 or greater then it uses gpupdate, if it is less than 5.1 then it uses secedit. After PowerShell has determined how it is going to update group policy the Invoke-WMIMethod is used create a new Windows process on the remote computer to start either gpupdate ("gpupdate /target:Computer /force") or secedit (“secedit /refreshpolicy machine_policy /enforce”).

Requires PowerShell v2



function Invoke-GPUpdate(){
param($ComputerName = ".")
$targetOSInfo = Get-WmiObject -ComputerName $ComputerName -Class Win32_OperatingSystem -ErrorAction SilentlyContinue
If ($targetOSInfo -eq $null){Write-Host -BackgroundColor Black -ForegroundColor Red "Unable to connect to $ComputerName"}
Else{
If ($targetOSInfo.version -ge 5.1){Invoke-WmiMethod -ComputerName $ComputerName -Path win32_process -Name create -ArgumentList "gpupdate /target:Computer /force /wait:0" Out-Null}
Else{Invoke-WmiMethod -ComputerName $ComputerName -Path win32_process -Name create –ArgumentList “secedit /refreshpolicy machine_policy /enforce“ Out-Null}
}
}



Example Usage

single computer:
“Invoke-GPUpdate –ComputerName computer01”

multiple computers from array:
$computerArray = “computer01”,“computer02”,“computer03”,“computer04”
$computerArray Foreach-Object{Invoke-GPUpdate -ComputerName $_}

multiple computers from a particular Active Directory OU (using Quest ActiveRoles for Active Directory):
Get-QADComputer -SearchRoot 'ou=computers,ou=locationA,dc=directory,dc=local' %{Invoke-GPUpdate -ComputerName $_.dnsname}

Wednesday, May 6, 2009

UPDATED (05/06/2009): Booting Windows 7/Server 2008 R2 from a VHD

*Updated for the RC builds (7100) of Windows 7 and Server 2008 R2

Original Post: Booting Windows 7/Server 2008 R2 from a VHD

Changes in RC

After downloading the bits for the RCs (build 7100) for Windows 7 and Server 2008 R2 I reloaded my laptop from scratch starting with Windows 7 x86 as my base OS. After 7 was up and running I followed the steps in my original post (Booting Windows 7/Server 2008 R2 from a VHD) to get Server 2008 R2 booting from VHD. There were only two differences between the beta and the RC I ran into in setting this up.

1) The first was after booting to the Server 2008 R2 media in trying to access the recovery console (I might have had this issue the in the beta and forgotten about it). After clicking on “repair your computer” it detects the Windows 7 installation and throws a error that the recovery tools are incompatible with the detected Operating System (the Windows 7 installation). At this point it didn’t allow me to proceed. The other option on this screen is to select an image to recover from. After selecting to recover from an image it searches for a supported recovery image (fails to find one). Once clicking on OK I was taken to the recovery console where I could then access the command shell and proceed.

2) The second difference I ran into was creating the VHD file. When in diskpart using the the “create vdisk” command it appears the default disk type has changed. In beta (build 7000) the default disk type was “expandable”. In RC (build 7100) the default disk type is “fixed”. From my original example I needed to change the command from “create vdisk file=’C:\VHDs\WinServ2008R2.vhd’ maximum=20480” to “create vdisk file=’C:\VHDs\WinServ2008R2.vhd’ maximum=20480 type=expandable”. While a fixed disk might slightly improve performance and keep me from over allocating space it’s not worth consuming all of the space up front.

 

bcdedit

I also realized I never discussed bcdedit.exe (Boot Configuration Data Edit). bcdedit is the tool you use to modify or remove (and manually create) entries in the Windows Boot Manager. bcdedit.exe is run from within Windows and needs Administrative rights to run (assuming you have UAC enabled make sure you launch an elevated prompt to make changes). Running bcdedit without any parameters displays the current entries and their values (example 1). Each available operating system is listed under a sections labeled “Windows Boot Loader”. To make any changes (including deleting any entry) you need to reference the unique “identifier” for that particular OS.

 

Modifying Boot Manager Entries

For each of my entries I wanted to change the text displayed at boot to include additional information about the version and boot location. For Window 7 I wanted to change the text from “Windows 7” to “Windows 7 (C: | RC, build 7100)” and for Server from “Windows Server 2008 R2” to "Windows Server 2008 R2 (C:\VHDs\WinServer2008R2.vhd | RC, build 7100)". As you can see in the output of Example 1 the OS you are currently in is referenced by a generic identifier “{current}” instead of a unique identifier.Ffor that reason the text used to change the descriptions varies slightly for the two entries:

Commands Used to Update my Descriptions
bcdedit /set "{096a20c7-3993-11de-b7cc-d1e341e28438}" description "Windows Server 2008 R2 (C:\VHDs\WinServer2008R2.vhd | RC, build 7100)"
bcdedit /set "{current}" description "Windows 7 (C: | RC, build 7100)"

 

Deleting Boot Manager Entries

Once you decide you are finished with a VHD booted OS removing it is a two step process. You delete the actual VHD (in my case “C:\VHDs\WinServer2008R2.vhd”) and delete the boot loader data. To delete the boot loader entry first run bcdedit to obtain the unique identifier. Next run “bcdedit /delete <unique identifier> /cleanup”. Specifying the cleanup parameter removes all references to the entry in addition to removing the entry from the Boot Manager table (you can get details on “/cleanup” by typing “bcdedit /delete /?”).

Example 1

PS C:\>bcdedit.exe

Windows Boot Manager
--------------------
identifier              {bootmgr}
device                  partition=\Device\HarddiskVolume3
description             Windows Boot Manager
locale                  en-US
inherit                 {globalsettings}
default                 {current}
resumeobject            {096a20ca-3993-11de-b7cc-d1e341e28438}
displayorder            {096a20c7-3993-11de-b7cc-d1e341e28438}
                        {current}
toolsdisplayorder       {memdiag}
timeout                 30

Windows Boot Loader
-------------------
identifier              {current}
device                  partition=C:
path                    \Windows\system32\winload.exe
description             Windows 7 (C: | RC, build 7100)
locale                  en-US
inherit                 {bootloadersettings}
recoverysequence        {096a20c4-3993-11de-b7cc-d1e341e28438}
recoveryenabled         Yes
osdevice                partition=C:
systemroot              \Windows
resumeobject            {096a20c2-3993-11de-b7cc-d1e341e28438}
nx                      OptIn

Windows Boot Loader
-------------------
identifier              {096a20c7-3993-11de-b7cc-d1e341e28438}
device                  vhd=[C:]\VHDs\WinServer2008R2.vhd
path                    \Windows\system32\winload.exe
description             Windows Server 2008 R2
locale                  en-US
inherit                 {bootloadersettings}
recoverysequence        {096a20c8-3993-11de-b7cc-d1e341e28438}
recoveryenabled         Yes
osdevice                vhd=[C:]\VHDs\WinServer2008R2.vhd
systemroot              \Windows
resumeobject            {096a20c6-3993-11de-b7cc-d1e341e28438}
nx                      OptOut

Tuesday, May 5, 2009

Windows Disc Image Burner

Natively burn ISO images to CD/DVD in Windows 7.

  1. right click ISO file
  2. “Burn disc image”…”Burn”
     disc image burner
  3. enjoy

That’s one less third party app to maintain.

Thursday, April 23, 2009

Booting Windows 7/Server 2008 R2 from a VHD

Windows 7 and Server 2008 R2 support a new ability to boot directly to a VHD instead of a physical hard drive volume. The biggest advantage I’ve had to using this as opposed to running an additional OS under Virtual PC (or similar) is that under this scenario the OS will have full access to ALL hardware components installed in the system (smartcard readers, biometrics, special input devices, etc). My scenario is that I have been running Windows 7 beta (x86, build 7000) on my laptop and I wanted a way to be able to test Server 2008 R2 (in particular Hyper-V settings/configuration options). With Server 2008 R2 only being released in 64 bit and wanting to take full advantage of the hardware in my laptop for testing Hyper-V I decided to configure 2008 R2 to boot from a VHD.

  1. Boot to the 2008 R2 DVD
  2. Instead of “Install now” click on “repair your computer”
  3. Click “next” to skip the operating system to repair selection.
  4. You should now be on the “System Recovery Options”. From here launch the command prompt.
  5. Optional: I like to place the VHD files that I am going to boot from in a root folder called “C:\VHDs”. To create this folder from the command prompt type “mkdir C:\VHDs”.
  6. Type “diskpart” and hit Enter. This should take you from the command shell prompt (ex: “x:\sources>”) to the diskpart prompt (ex: “DISKPART>”).
  7. Optional: Verify the volume you want to place he VHD on  by typing “list volume”.
  8. Now we need to create the VHD file. “create vdisk file=’<full path and file name>’ maximum=<max size of VHD in MB>” (example: “create vdisk file=’C:\VHDs\WinServ2008R2.vhd’ maximum=20480). By default the disk will be created as a dynamically expanding disk. If you prefer the entire size of the VHD to be pre-allocated add the option “type=fixed” (example: “create vdisk file=”C:\VHDs\WinServ2008R2.vhd” maximum=20480 type=fixed).
    Note: if you used a fixed size VHD that is large be aware it may take some time to create and allocate the space for the VHD.
  9. Once the VHD has been created (you should have received the response “DiskPart successfully created the virtual disk file”) you need to select the disk and connect it.
    1. To select the disk (so we can perform additional actions against it) type “select vdisk file=’<full path and file name to VHD previously created>’” (from the example above would be “select vdisk file=’C:\VHDs\WinServ2008R2.vhd’ ”).
    2. To attach the disk so We can install the OS to it type “attach vdisk”
  10. At this point you are ready to install Windows. To return to the installation screen (DO NOT REBOOT or you will need to re-select and re-attach the vdisk as we did in step 9) type exit in at the DiskPart prompt to return to the command shell. Type exit again at the command shell to prompt to return to the “System Recovery Options”. Now close the Recovery Options by clicking on the close Window box (the “X”) in the top right corner.
    NOTE: if you do accidentally reboot you only need to reattach the VHD using the commands in step 9.
  11. You should now be at the “Install Windows” screen. Click “Install Now” to proceed. When you get to the disk selection (“Where do you want to install Windows?”) make sure you select the VHD and not the physical drive holding the VHD (and the original Windows 7 installation).
    Tip: The VHD disk should show “Disk # Unallocated Space” in the name.

Tuesday, April 21, 2009

Creating a Windows 7 Search Connector for SharePoint/MOSS 2007

After using search connectors in Windows 7 for several public Internet websites (see Image 1 of a search on Wikipedia) I wanted to add a connector to be able to search my corporate SharePoint 2007 sites.

Image 1
searchConnector1

After reviewing a few examples from Internet sites and with a little digging on on MSDN for the Enterprise Search Syntax Reference for MOSS/SharePoint (http://msdn.microsoft.com/en-us/library/aa637082.aspx) it turned out to be surprisingly easy. Search Connectors are denoted by an osdx file extension. Double clicking on the osdx file will create the search connector (located under your user profile; c:\users\<username>\searches) and create a shortcut in your Windows Explorer favorites sidebar.

Example 1
Example 1 below shows the code used to create a basic Search Connector that will include all sites within your SharePoint deployment. Within Example 1 the sections/variables that you will need to change are indicated below. To create a Search Connector for your SharePoint site copy the code from example 1 and paste it into notepad. Once you have the code in notepad change the three variables for your environment then save the file with an osdx extension (ex: “SharePoint Search (All).osdx”).

Example 1 Variables:
ShortName: The shortname is the display name of the Favorites folder that will appear in Windows Explorer. Make this value unique and make sure it represents the scope of the search.
Description: As the name states this is the description for the search. This one can be more verbose than the ShortName but to be honest it rarely shows up. This value is set as a file property on the Search Connector object (located  under “c:\users\<username>\searches”).
sharepoint_url: This one’s not a tag so you will have to look for it in the middle of the line (lines 5 & 6). Make sure this base URL is is set to the URL for your SharePoint deployment.

 Example 1: Code for default all sites (default search scope “All Sites”)

<?xml version="1.0" encoding="UTF-8"?>
<OpenSearchDescription xmlns="
http://a9.com/-/spec/opensearch/1.1/" xmlns:ms-ose="http://schemas.microsoft.com/opensearchext/2009/">
<ShortName>SharePoint (All Sites)</ShortName>
<Description>Search the SharePoint Server.</Description>
<Url type="application/rss+xml" template="
http://sharepoint_url/searchcenter/_layouts/srchrss.aspx?k={searchTerms}&amp;s=All%20Sites"/>
<Url type="text/html" template="
http://sharepoint_url/searchcenter/Pages/Results.aspx?k={searchTerms}&amp;s=All%20Sites"/>
<ms-ose:ResultsProcessing format="application/rss+xml">
<ms-ose:LinkIsFilePath>-1</ms-ose:LinkIsFilePath>
</ms-ose:ResultsProcessing>
</OpenSearchDescription>


Example 2
Example 2 adds on to what we have already learned about search connectors by making use of the default Search Scope for “People” within SharePoint. The Search Scopes are preconfigured filters/indexes defined within SharePoint. By referencing the “People” search scope then we can create a search connector that will search for an SharePoint user’s information.

Example 2 Variables:
In addition to the same variables as Example 1 we need to specify the SharePoint Search Scope. The Search Scope is defined by the variable “s” in the SharePoint url request string. This variable will need updated in both lines 5 & 6, the same as “sharepoint_url”.

Example 2: Code to search for People (default search scope “People”)

<?xml version="1.0" encoding="UTF-8"?>
<OpenSearchDescription xmlns="
http://a9.com/-/spec/opensearch/1.1/" xmlns:ms-ose="http://schemas.microsoft.com/opensearchext/2009/">
<ShortName>SharePoint (People Search)</ShortName>
<Description>Search for people on the SharePoint Server.</Description>
<Url type="application/rss+xml" template="
http://sharepoint_url/searchcenter/_layouts/srchrss.aspx?k={searchTerms}&amp;s=people"/>
<Url type="text/html" template="
http://sharepoint_url/searchcenter/Pages/Results.aspx?k={searchTerms}&amp;s=people"/>
<ms-ose:ResultsProcessing format="application/rss+xml">
<ms-ose:LinkIsFilePath>-1</ms-ose:LinkIsFilePath>
</ms-ose:ResultsProcessing>
</OpenSearchDescription>

Example 3
Example 3 continues the use of SharePoint search scopes. In this case we are utilizing multiple custom defined search scopes (http://office.microsoft.com/en-gb/sharepointserver/HA011648521033.aspx) to include on content from certain sites with SharePoint.

Example 3 Variables:
As with Example 2 the key difference from the original search connector is in defining the “s” variable for the custom Search Scope. In this case though we are specifying multiple search scopes in the “s” variable by separating them with a %2c (the ASCII html code for a comma). In example 2 the search connector definition looked like this “s=people”. Now we are searching across the custom search scopes “search_scope1”, “search_scope2”, and “search_scope3” by using the following definition “s=search_scope1%2csearch_scope2%2csearch_scope3”

Example 3: Code for custom search sites (default search scope)

<?xml version="1.0" encoding="UTF-8"?>
<OpenSearchDescription xmlns="
http://a9.com/-/spec/opensearch/1.1/" xmlns:ms-ose="http://schemas.microsoft.com/opensearchext/2009/">
<ShortName>SharePoint (search_scope)</ShortName>
<Description>Search the SharePoint Server (search_scope).</Description>
<Url type="application/rss+xml" template=
http://sharepoint_url/searchcenter/_layouts/srchrss.aspx?k={searchTerms}&amp;s=search_scope1%2csearch_scope2%2csearch_scope3/>
<Url type="text/html" template="
http://sharepoint_url/searchcenter/Pages/Results.aspx?k={searchTerms}&amp;s=search_scope"/>
<ms-ose:ResultsProcessing format="application/rss+xml">
<ms-ose:LinkIsFilePath>-1</ms-ose:LinkIsFilePath>
</ms-ose:ResultsProcessing>
</OpenSearchDescription>

Deleting Search Connectors
If/When you decide to delete a search connector that is no longer need make sure you delete the actual search connector itself that is located under c:\users\<username>\searches as well as the Windows Explorer favorites. There is no harm in only deleting the favorite except that when you go to reinstall the search connector you’ll notice te new favorite gets incremented up with “(#)'”.

Followers