May 2008 - Posts
In our SCOM 2007 environment, we get a lot of the below alert:
Alert: Alert generated by Send Queue % Used Threshold
Source: xyz.related.com
Path: xyz.related.com
Last modified by: System
Last modified time: 5/22/2008 6:29:13 PM Alert description: The current value of 60.2739067077637 is outside the accepted threshold
Alert view link: "http://whatever:51908/default.aspx?DisplayMode=Pivot&AlertID={d815369d-b5f9-4b03-a572-fa9857e781af}"
Notification subscription ID generating this message: {4B6F3971-955E-1491-6D82-5C22F1466FC2}
Stefan Stranger has a Blog about this. He mentioned that we need to increase the size of the following registry key:
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\HealthService\Parameters\Management Groups\%Management Groupname%\MaximumQueueSizeKb]
Which I have been using to fix the alert and for some server, I even go one step further changing the size to 61440. But I kind tired of doing this on each server – the solution is PowerShell and remote registry!
Mow has a blog about using PowerShell to change the remote registry key.
Enlighten by their work, I come up with the below script to use PowerShell changing registry key on multiple remote server and report in excel:
$a = New-Object -comobject Excel.Application
$a.visible = $True
$b = $a.Workbooks.Add()
$c = $b.Worksheets.Item(1)
$c.Cells.Item(1,1) = "Server Name"
$c.Cells.Item(1,2) = "Old MaximumQueueSizeKb"
$c.Cells.Item(1,3) = "New MaximumQueueSizeKb"
$c.Cells.Item(1,4) = "Report Time Stamp"
$d = $c.UsedRange
$d.Interior.ColorIndex = 19
$d.Font.ColorIndex = 11
$d.Font.Bold = $True
$intRow = 2
$colComputers = get-content C:\MachineList.txt
foreach ($strComputer in $colComputers)
{
$c.Cells.Item($intRow,1) = $strComputer.Toupper()
Function GetRegInfo
{
$reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $strComputer)
$key="SYSTEM\CurrentControlSet\Services\HealthService\Parameters\Management Groups\XYZ Enterprise Apps"
$regKey = $reg.OpenSubKey($key)
$max = $regkey.GetValue("MaximumQueueSizeKb")
If($max -eq '15360')
{
$c.Cells.Item($intRow,2).Interior.ColorIndex = 3
$c.Cells.Item($intRow,2) = $max
#$True make the registry key writable
$regKey = $reg.OpenSubKey($key, $True)
$regkey.SetValue('MaximumQueueSizeKb', 30720)
$newmax = $regkey.GetValue("MaximumQueueSizeKb")
$c.Cells.Item($intRow,2) = $newmax
}
Else
{$c.Cells.Item($intRow,2) = $max}
}
GetRegInfo
$c.Cells.Item($intRow,4) = Get-date
$intRow = $intRow + 1
}
$d.EntireColumn.AutoFit()
cls
Happy PowerShelling and Sharing!
$erroractionpreference = "SilentlyContinue"
$a = New-Object -comobject Excel.Application
$a.visible = $True
$b = $a.Workbooks.Add()
$c = $b.Worksheets.Item(1)
$c.Cells.Item(1,1) = "Organization"
$c.Cells.Item(1,2) = "Server Name"
$c.Cells.Item(1,3) = "Operating System"
#$c.Cells.Item(1,4) = "IP Address"
$c.Cells.Item(1,4) = "Service Packs"
$c.Cells.Item(1,5) = "System Type"
$c.Cells.Item(1,6) = "Install Date"
$c.Cells.Item(1,7) = "Manufacturer"
$c.Cells.Item(1,8) = "Model"
$c.Cells.Item(1,9) = "Service Tag"
$c.Cells.Item(1,10) = "Serial Number"
$c.Cells.Item(1,11) = "Number of Processors"
$c.Cells.Item(1,12) = "Total Phsyical Memory (GB)"
$c.Cells.Item(1,13) = "Last Reboot Time"
$c.Cells.Item(1,14) = "Report Time Stamp"
$d = $c.UsedRange
$d.Interior.ColorIndex = 19
$d.Font.ColorIndex = 11
$d.Font.Bold = $True
$intRow = 2
$colComputers = get-content C:\MachineList.txt
foreach ($strComputer in $colComputers)
{
$OS = get-wmiobject Win32_OperatingSystem -computername $strComputer
$Computer = get-wmiobject Win32_computerSystem -computername $strComputer
$Bios =get-wmiobject win32_bios -computername $strComputer
$c.Cells.Item($intRow,1) = $OS.Organization
$c.Cells.Item($intRow,2) = $strComputer.Toupper()
$c.Cells.Item($intRow,3) = $OS.Caption
#$c.Cells.Item($intRow,4) = $IP.IPaddress[0]
$c.Cells.Item($intRow,4) = $OS.CSDVersion
$c.Cells.Item($intRow,5) = $Computer.SystemType
$c.Cells.Item($intRow,6) = [System.Management.ManagementDateTimeconverter]::ToDateTime($OS.InstallDate)
$c.Cells.Item($intRow,7) = $Computer.Manufacturer
$c.Cells.Item($intRow,8) = $Computer.Model
$c.Cells.Item($intRow,9) = $Bios.serialnumber
$c.Cells.Item($intRow,10) = $OS.SerialNumber
$c.Cells.Item($intRow,11) = $Computer.NumberOfProcessors
$c.Cells.Item($intRow,12) = "{0:N0}" -f ($computer.TotalPhysicalMemory/1GB)
$c.Cells.Item($intRow,13) = [System.Management.ManagementDateTimeconverter]::ToDateTime($OS.LastBootUpTime)
$c.Cells.Item($intRow,14) = Get-date
$intRow = $intRow + 1
}
$d.EntireColumn.AutoFit()
cls
We are currently working on a File server migration project. The plan is to migrate the current Window 2000 file server to a three nodes Windows Server 2003 Clustered file server. All the disks are on the SAN. Instead copy files or restore files from backup. We decided to re-map the SAN volumes to the new clusters, this will carry over all the data and NTFS permissions except – it won’t carry over the Shares as the share information stored in the OS registry.
My fellow MVP friend Jeremy Moskowitz helped me identified the registry key for the shares
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\LanmanServer\Shares\ and
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\LanmanServer\Shares\Security
We tested it out and it is all happy except the shares will not fail over. Then we realized the fact that we need to create the File Share Resource through Cluster Administrator not Windows Explorer. Export/Import registry key is equivalent to creating shares through Windows Explorer. But creating hundreds of shares through Cluster Administrator even by script is daunting task and further more – it is not optimal configuration anyway!
Further digging point me to this KB256926 and our problem solved!
All we need to do as instructed in the above article
1, Create one single (root volume) cluster file share resource.
2, Grant everyone full control share-level permissions in cluster administrators.
3, Using the Parameters tab for the root cluster file share resource, click to select the Share all sub-directories check box.
4, Set appropriate NTFS permissions.
That is all we need to do for the new users folder created!
In case you don’t already know, Windows PowerShell V2 Community Technology Preview 2 (CTP2) is available for download Here
Another Pre-Memorial bonus for PowerShell fans is that Windows PowerShell Scriptomatic V1.0 now avaliable and you can download it Here
Here is a PowerShell script to install SCOM agent on multiple servers.
In my previous blog Re-Uniting PowerShell Console I explained how you can run SCOM related PowerShell script in regular PowerShell console.
Now continue on
PS Microsoft.EnterpriseManagement.OperationsManager.Client\OperationsManagerMonitoring::NYTWOPMP01> C:\InstallSCOMAgent.ps1
Here is what’s in InstallSCOMAent.ps1 script – becareful with the path, as SCOM seems very picky about it. You have to use full path even the serverlist is in the same directory with InstallSCOMAgent.ps1
$creds = Get-Credential
#Create an array $Servers for a list of servers
$servers = get-content c:\ServerList.txt
$DiscoCnfg = New-WindowsDiscoveryConfiguration -computername:$servers -performverification: $true -actionaccount:$creds -computertype: "server"
$ms = Get-rootManagementServer
#You have to Discover the computer first
$DiscoResults = Start-Discovery -managementserver $ms -windowsdiscoveryconfiguration:$DiscoCnfg
install-agent -ManagementServer $ms -AgentManagedComputer: $DiscoResults.custommonitoringobjects
My productivity goes up significantly because of this! 
I am currently working on a file server migration project, part of the task is to move users TsProfilePath from \\ServerA\Profiles\%username% to \\ServerB\Profiles\%username%
Microsoft recommends to use GPO to Change a user's Terminal Services profile path
I payed with that a little bit. While find the GPO setting is easy but I have trouble to test it out. As some article mention that I need to put Citrix servers in a OU and then set GPO for that OU and it is a kind complicated and I don’t have the test environment to test it.
I then remember that we live in PowerShell age – after some trials and errors – here is the solution
Again I need to use Quest AD extension mentioned in yesterday’s blog
Here is old way
$users = Get-QADUser -SearchRoot 'xyz.com/TestOU'
foreach ($u in $users)
{$u.TsProfilePath = '\\ServerB\profiles\' + $u.sAMAccountName; $u.CommitChanges()}
Here is new way
Get-QADUser -SearchRoot 'xyz.com/TestOU'|%{$_.TsProfilePath ='\\ServerB\profiles\' + $_.sAMAccountName;$_.CommitChanges();}
Basically it does the same thing and the new “way” is a one liner which is neat. I finally passed that foreach hurdle!
No matter you use GPO or PowerShell, you still need to copy users TS profile from ServerA to Server B. Here we just change the pointer in user’s AD property
I want to warn you that Playing this in a production environment is very dangerous and it will easily mess things up!
That’s why I use -searchRoot to target a small test OU and even that I didn’t use $u.CommitChanges() until I am absolutely sure what’s going to happen.
Finally if you are the “brave” guy and ready to do this for your entire domain – DON’T DO THIS LIGHTLY!!!
Get-QADUser -sizelimit 0|%{$_.TsProfilePath ='\\ServerB\profiles\' + $_.sAMAccountName;$_.CommitChanges();}
In my previous script PowerShell script to query ADSI and get user object properties
I created excel object and using PowerShell/ADSI to interact with AD and send the output to excel.
At the time of that witting, I was proud of what I did – otherwise, I wouldn’t publish it! 
But not anymore!
I could get the similar results using the below script – one liner!
Get-QADUser -SizeLimit 0 -ip sAMAccountName, homedirectory, homedrive, Mail | Select name, sAMAccountName, HomeDirectory, HomeDrive, TsProfilePath, Mail |export-csv ADUsers.csv
Of course, in order to run the above script you need to download and install ActiveRoles Management Shell for Active Directory from Quest.
Let me explain the above script
Get-QADUser which will retrieve all users in a domain or container that meet the specified conditions. I heard Microsoft own version of PowerShell extension is in the work and it will be something like Get-ADUser. Quest was gracious enough to leave that cmdlet to Microsoft!
-Sizelimit 0 means return all – the default will return 1000.
You have to include -IncludeProperties (-ip) otherwise those properties won’t show. Thanks my fellow MVP friend Demitry Sotnikov, the author of Quest PowerShell extension for the tip.
Last but not list export-csv cmdlet will export the results to an csv file which as you know is excel’s poor cousin. Even though it is lacking some of the format such as Bold, autofit and colors etc. But I will still trade this one liner with my one page script!
There is always a better way…
Here are a few cmdlets to work with distribution group in exchange 2007
New-DistributionGroup – Creates a new distribution group
Set-DistributionGroup – Set Properties on a distribution group
Get-DistributionGroup – Retrieves properties of a distribution group
Remove-DistributionGroup – Deletes a distribution group
…
If you want to work with DynamicDistributionGroup, just replace DistributionGroup with DynamicDistributionGroup.
As always you can get details by get-help cmdlet -full
How you add member(s) to an existing distribution group?
Add-DistributionGroupMember -Id ITOps -Member ‘yli’
What if you want to grant someone manage a distributiongroup membership permission?
Set-DistributionGroup -id ITOps -ManagedBy ‘Yli’
That actually doesn’t work. It is the same as you use Set-Mailbox cmdlet to set Exchange specific properties and the Set-User cmdlet to set basic Active Directory properties, Here you need to use Set-Group because this action creates a link to another AD account who will manage the group! So the below cmdlet will accomplish the above task!
Set-Group -id ITOps – ManagedBy ‘yli’
I will add a bonus here – what if you change your mind and want to remove someone the manage distributiongroup permission?
Set-Group -id ITOps – ManagedBy $null
As you must already realize that you can’t be an exchange 2007 administrator without knowing or learning PowerShell. As you have to use PowerShell to accomplish some of the tasks and for some tasks even though you can do it in EMC (Exchange Management Console) but Microsoft recommend that you do it through Exchange Cmdlet.
If you manage Exchange 2007 in a clustered environment (currently only supported for mailbox server role). You must have used the below cmdlet to transfer Exchange Server 2007 clustered mailbox server (CMS) to a passive cluster node.
Move-ClusteredMailboxServer –Identity:NYCESP02 –targetmachine:NYCMBXP03
What it does is to make the current passive node NYCMBXP03 an active node on cluster NYCESP02
For details about the above cmdlet, type get-help Move-ClusteredMailboxServer –full in PowerShell prompt.
Sounds easy? But there is a catch – see below
PS C:\Documents and Settings\yl.admin\My Documents\PS> Get-ClusteredMailboxServerStatus -Identity nycesp02
Identity : NYCESP02
ClusteredMailboxServerName : NYCESP02.xyz.com
State : Online
OperationalMachines : {NYCMBXP03 <Active>, NYCMBXP04 <Quorum Owner>}
FailedResources : {}
IsValid : True
ObjectState : Unchanged
While it indeed transferred the owner for the Exchange group but the quorum or the cluster group owner is still on NYCMBXP04 (the previous active node).
There is nothing wrong with that and it is actually by design: The move-ClusteredMailboxserver cmdlet only moves the Exchange group and there is no impact on the cluster group!
Unfortunatly for some Exchange 2007 administrator they just leave their Exchange cluser like that! They were told by Microsoft and others that the recommended way to move Exchange group is to use the above cmdlet. They get it then they notice the fact the cluster group wasn’t moved and they are “concerned” to move the cluster group through cluster administrator GUI because they think that’s not the right way. As the result they leave their Exchange cluster in the “split-brain” mode – the exchange group is owned by one node and the cluster group is owned by another node!
While Microsoft indeed recommed to use Move-ClusteredMailboxServer to move the Exchange group but that’s only for the Exchange group, it has no impact on the cluster group and it doesnt’ prevent you use the cluster administrator GUI to move the cluster group! You actually need to do that!
Here is a PowerShell script to identify the top 10 user who has the biggest mailbox on your exchange 2007 server and output the result to Internet Explorer
$strComputer = (Read-Host "Please Enter The Server Name").Toupper()
$ie = new-object -comobject InternetExplorer.Application
$ie.visible = $True
$ie.navigate("About:Blank")
$ie.document.title = "Top 10 Mailbox Users On $strComputer"
$ie.toolbar = "1"
$ie.statusbar = ""
$BigMailUsers = Get-MailboxStatistics -server $strComputer |sort-object -Property totalitemsize -des |select-object Displayname, ItemCount,
@{name='TotalItemSize(MB)';expression={$_.totalitemsize/1MB}} -first 10 |Convertto-html
$ie.Document.Body.InnerHTML = $BigMailUsers
$ie.Document.body.Bgcolor = "MintCream"
$ie.Document.FgColor = "MidnightBlue"
When you build Window 2003 R2 SP2 server – by default it has Microsoft.NET Framework 2.0 Service Pack 1 and Microsoft .NET Framework 3.0 Service Pack1 installed. You will notice ASP.NET v2.0.50727 is MIA(missing in action) in Web Services Extension in IIS manager. How you make it appear and make it as an “allowed” service?
The dumb way is to remove .NET Framework 3.0 SP1 and .NET Framework 2.0 SP1 then download the .NET Framework 2.0 and 3.0. After installing .NET Framework 2.0 the ASP.NET v2.0.40727 will show up. If needed, you can reinstall SP1 for both version which is quite boring process. Guess what, that’s what I did when I first notice the problem.
The smart way (which I am doing now!)is to start a DOS window – change to the following directory
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727> or C:\WINDOWS\Microsoft.NET\Framework64\v2.0.50727> for 64 bit
Type aspnet_regiis.exe – i
ASP.NET will register itself and show up in Web Service Extensions!
Recently I am working on to build a SharePoint staging environment for my company. This is a brand new staging environment. So I created the AD accounts and did all those setspn, account delegation stuff. Created the sites/site collections following our build docs. It was a seemly successful drill except one issue – I can’t open the default sharepoint site on the sharepoint server – sharepoint.xyz-stage.com even though the account I log on (mossservices) is the account I use to build the entire sharepoint sites and is in local administrators group. But I can open the site from another machine. Here is some error in event viewer:
The application-specific permission settings do not grant Local Activation permission for the COM Server application with CLSID
{61738644-F196-11D0-9953-00C04FD919C1}
to the user xyz-STAGE\MOSSPortalAdmin SID (S-1-5-21-3439712273-356373770-983286714-1126). This security permission can be modified using the Component Services administrative tool.
The application-specific permission settings do not grant Local Activation permission for the COM Server application with CLSID
{61738644-F196-11D0-9953-00C04FD919C1}
to the user xyz-STAGE\MOSSServices SID (S-1-5-21-3439712273-356373770-983286714-1118). This security permission can be modified using the Component Services administrative tool.
Search registry for the above CLSID {61738644-F196-11D0-9953-00C04FD919C1} – it’s point to IIS Admin and IIS WAMREG Admin
Here is what I did to fix the issue. Start-run - type dcomcnfg and browser to DCOM config and look for IIS admin service and grant administrators local access permission and did the same thing for IIS WAMREG Admin Service. Also make sure the above mentioned accounts are part of local administrators group.
I can now open the site without any issues!