Tag Archives: MimbolovePowershell

PowerShell Functions: Get OpsMgr Alert Generating Rules and Monitors

Written by Tao Yang

This is my second post today. Bad weather, both wife and daughter have got flu. So I’m sitting home catching up with blogs…

I wrote 2 functions as part of a PowerShell script I’ve been working on: Get-AlertRules and Get-AlertMonitors.

As the names suggest, these two functions get all Rules / Monitors of a particular monitoring class that generate alerts.

I didn’t end up using these 2 functions in my script, but I thought they are too good to be trashed. so I thought I’ll put them here for future reference.

Get-AlertRules:

Function Get-AlertRules
{
PARAM (
[Parameter(Mandatory=$true,HelpMessage="OpsMgr Management Group Connection" )][Microsoft.EnterpriseManagement.ManagementGroup] $ManagementGroup,
[Parameter(Mandatory=$false,HelpMessage="Monitoring Class Name" )][string] $MonitoringClassName = $null
)
$arrAlertRules = New-object System.Collections.ArrayList
#Get GenerateAlert WriteAction module
$HealthMPId = [guid]"0abff86f-a35e-b08f-da0e-ff051ab2840c" #this is unique
$HealthMP = $MG.GetManagementPack($HealthMPId)
$AlertWA = $HealthMP.GetModuleType("System.Health.GenerateAlert")
$AlertWAId = $AlertWA.Id
#firstly get all monitoring classes
#Populate Search criteria
If ($MonitoringClassName)
{
$strClassCriteria = "Name = '$MonitoringClassName'"
} else {
$strClassCriteria = "Name LIKE '%'"
}
$ClassCriteria = New-Object Microsoft.EnterpriseManagement.Configuration.MonitoringClassCriteria($strClassCriteria)
$MonitoringClasses = $MG.GetMonitoringClasses($ClassCriteria)
Foreach ($MC in $MonitoringClasses)
{
$MCId = $MC.Id
$strRuleCriteria = "TargetMonitoringClassId = '$MCId'"
$RuleCriteria = New-Object Microsoft.EnterpriseManagement.Configuration.MonitoringRuleCriteria($strRuleCriteria)
$Rules = $MG.GetMonitoringRules($RuleCriteria)
Foreach ($rule in $Rules)
{
#Unfortunately, we cannot use a member module name/id in MonitoringRUleCriteria.
#So we have to manually filter out the rules with GenerateAlert Write Action Module
#Check if it has a GenerateAlert WriteAction module
$bAlertRule = $false
Foreach ($WAModule in $Rule.WriteActionCollection)
{
if ($WAModule.TypeId.Id -eq $AlertWAId)
{
#this rule generates alert
$bAlertRule = $true
} else {
#need to detect if it's using a customized WA which the GenerateAlert WA is a member of
$WAId = $WAModule.TypeId.Id
$WASource = $MG.GetMonitoringModuleType($WAId)
#Check each write action member modules in the customized write action module...
Foreach ($item in $WASource.WriteActionCollection)
{
$itemId = $item.TypeId.Id
If ($ItemId -eq $AlertWAId)
{
$bAlertRule = $true
}
}
}

if ($bAlertRule)
{
#Add to arraylist
[void]$arrAlertRules.Add($rule)
}
}
}
}
,$arrAlertRules
}

Get-AlertMonitors:

Function Get-AlertMonitors
{
PARAM (
[Parameter(Mandatory=$true,HelpMessage="OpsMgr Management Group Connection" )][Microsoft.EnterpriseManagement.ManagementGroup] $ManagementGroup,
[Parameter(Mandatory=$false,HelpMessage="Monitoring Class Name" )][string] $MonitoringClassName = $null
)
$arrAlertMonitors = New-object System.Collections.ArrayList
#firstly get all monitoring classes
#Populate Search criteria
If ($MonitoringClassName)
{
$strClassCriteria = "Name = '$MonitoringClassName'"
} else {
$strClassCriteria = "Name LIKE '%'"
}
$ClassCriteria = New-Object Microsoft.EnterpriseManagement.Configuration.MonitoringClassCriteria($strClassCriteria)
$MonitoringClasses = $MG.GetMonitoringClasses($ClassCriteria)
Foreach ($MC in $MonitoringClasses)
{
$MCId = $MC.Id
$strMonitorCriteria = "TargetMonitoringClassId = '$MCId' AND AlertOnState IS NOT NULL"
$MonitorCriteria = New-Object Microsoft.EnterpriseManagement.Configuration.MonitorCriteria($strMonitorCriteria)
$Monitors = $MG.getmonitors($MonitorCriteria)
Foreach ($Monitor in $Monitors)
{
#Add to arraylist
[void]$arrAlertMonitors.Add($Monitor)
}
}
,$arrAlertMonitors
}

Both functions are expecting an OpsMgr management group connection and the name (not the display name, but the Class ID from the management pack where the class is defined). so in order to use these 2 functions, I’ll need 2 other functions:

Load-SDK:

function Load-SDK()
{
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.EnterpriseManagement.OperationsManager.Common") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.EnterpriseManagement.OperationsManager") | Out-Null
}

Get-MonitoringClass:

Function Get-MonitoringClass
{
PARAM (
[Parameter(Mandatory=$true,HelpMessage="OpsMgr Management Group Connection" )][Microsoft.EnterpriseManagement.ManagementGroup] $ManagementGroup,
[Parameter(Mandatory=$true,HelpMessage="Monitoring Class Display Name" )][string] $MonitoringClassDisplayName
)
#Populate Search criteria
$strClassCriteria = "DisplayName = '$MonitoringClassDisplayName'"
$ClassCriteria = New-Object Microsoft.EnterpriseManagement.Configuration.MonitoringClassCriteria($strClassCriteria)
#Search monitoring class
$MonitoringClasses = $MG.GetMonitoringClasses($ClassCriteria)
$MonitoringClasses
}

as the name suggests, Load-SDK function loads OpsMgr SDK, when can then create the connection to the management group. Get-MonitoringClass function gets the Monitoring Class object based on it’s display name (the name you see in the Operations Console), such as this one:

SNAGHTML1f11d89

Here’s an example of how to these functions:

#Load SDK DLL's
Load-SDK

#Connect to the management group via management server "OpsMgrMS01":
$MGConnSetting = New-Object Microsoft.EnterpriseManagement.ManagementGroupConnectionSettings("OPSMGRMS01")
$MG = New-Object Microsoft.EnterpriseManagement.ManagementGroup($MGConnSetting)

#Get the monitoring class
$MonitoringClassDisplayName = "Data Access Service"
$MonitoringClass = Get-MonitoringClass $MG $MonitoringClassDisplayName
$MonitoringClassName = $MonitoringClass.Name

#Display Monitoring Class Name
$MonitoringClassName

#Get Alert rules
$AlertRules = Get-AlertRules $MG $MonitoringClassName

#Rule Count
$alertRules.count

#Alert Monitors
$AlertMonitors = Get-AlertMonitors $MG $MonitoringClassName

#Monitor Count
$AlertMonitors.Count

SNAGHTML1f339a2

Logics in these 2 functions:

Get-AlertRules:

Searching for rules either have the “System.Health.GenerateAlert” module from System.Health.Library MP as a Write Action member module, or one of the rule’s Write Action member modules has “System.Health.GenerateAlert” as its member.

Get-AlertMonitors:

This function is much easier to write than Get-AlertRules. I’ simply search for monitors that “AlertOnState” property is not NULL. Please keep in mind this function does not only return unit monitors, but also aggregate and dependency monitors.

Both functions return a “System.Collections.ArrayList” containing the rules / monitors. Since I used the OpsMgr SDK directly, instead of it’s PowerShell snapin or module. these functions should work in both 2007 and 2012. – And this is one of the reasons why I always just use SDK, hardly use the snapin or the module :)

I’ve also zipped up all the code used in this article. You can download them HERE. I know it’s a bit hard to read the code in WordPress :)

Remotely Powering On and Off My Entire Home Lab

Written by Tao Yang

RemoteMy home lab consists of 3 PCs running Hyper-V and a HP Proliant Microserver N54L running SCVMM. I have previously blogged the lab setup in a 2-part blog posts (Part 1, Part 2). These 2 blog articles was written back in October 2012, although there are few changes in the current setup (new hardware, etc), but the overall setup is pretty much the same.

All 4 machines in my lab have been constantly running 24×7, except when we go on holidays or there’s a power outage (which doesn’t happen very often). This is largely because I just can’t be bothered to spend time start and shutdown all the physicals and virtuals every time I use the lab, not to mention I often access my lab when I’m in the office via RDP using my Surface Pro 2 with an external monitor. Because all of the computers are PC grade hardware, there are no out-of-band management cards (i.e. iLo, DRAC, etc.) on these boxes, I had no way to remotely start them when I was in the office.

In order to reduce the “carbon footprint”, and more importantly, my electricity bill, I have been wanting to automate the the start and shutdown process of the entire lab for a while. Last weekend, I finally got around to it, and accomplished it by using only Wake On LAN (WOL) and PowerShell (with PowerShell Web Access, WinRM and CredSSP).

Because one of the PCs in my lab is my main desktop (running Windows 8.1 with Hyper-V role enabled), this PC is always running. my solution is to use this desktop (called “Study”) to interact with other physical computers in the lab. I’ll now go through the steps I took to archive this goal:

1. confirm / configure Wake-On-LAN on all physical computers in the lab.

I installed a freeware called AquilaWOL on my “Study” PC, made sure I can WOL all other computers.

image

During my testing, the HP Microserver and one of the Hyper-V box (HyperV01, the one with the Intel motherboard) had no problem at all. However, the other HyperV box HyperV02, would not WOL. after some research, it seemed like a known issue with the motherboard that only be able to WOL when the computer is at sleep, not when it’s powered off. Luckily other than the on-board Marvell NIC, I also have a dual port Intel GB NIC and a single port Intel desktop GB NIC on this computer. the dual port NIC also wouldn’t work. but the desktop NIC worked :)

2. Installed a Windows Server 2012 R2 virtual machine on my “Study” PC.

I named this VM “JUMP01” because I intend to use this as a jump box. I connected this VM to the virtual switch  which is on the same subnet as all physical computers – so I don’t rely on switch/routers to relay WOL packets. I also need my AD environment to be available when running the script, but because I have a domain controller already running as a VM on my Study PC, no additional VM’s are required.

3. Installed and configured PowerShell Web Access on the Jump server.

So I don’t have to RDP to the jump server to run the scripts. This also enables me to power on / off the lab from any mobile devices with a browser. I have followed my previous blog post to install and configure PSWA. I also wrote a PowerShell module to resize PowerShell console size to make PSWA more user-friendly for mobile devices.

4. Developed PowerShell scripts to power on and power off the physical and virtuals.

I wrote 2 scripts: start-lab.ps1 and stop-lab.ps1. both scripts read required information from a XML file (labconfig.xml). this XML file contains all required information for my lab environment.

SNAGHTML6bd3b2

The PowerShell scripts utilise WinRM and CredSSP to interact with each physical computers (using PSSessions and Invoke-Command).

Below is a list of steps each script performs:

Start-Lab.ps1:

  1. Read XML, get information for all computers that are a member of the lab
  2. ping each lab member, send WOL magic packet if ping failed
  3. wait for 90 seconds (configurable via XML)
  4. Check OS readiness (configurable via XML)
    • Minimum up time
    • all required services are running
  5. Once the OS is ready on the Hyper-V hosts, start VMs in groups hardcoded in the script (based on my naming standard in the lab).
    • firstly start the CentOS VM configured as routers (they are configured to auto start with the host, but just in case they did not start).
    • Then start the domain controller
    • Then start all VMs hosting SQL databases (OpsMgr DB, ConfigMgr site servers, Service Manager DB, etc).
    • Then start all other VMs except OpsMgr management servers
    • Lastly, start all OpsMgr management servers (they must be started at the end so I don’t get any alerts).

Stop-Lab.ps1:

  1. Read XML, get information for all computers that are a member of the lab
  2. ping each lab member, ignore the lab member if it does not respond to ping
  3. shutdown VM’s in order (which is the reverse order as the start-lab.ps1)
  4. double check if all VM’s are completely shutdown, if not, forcibly turn them off
  5. shutdown Hyper-V servers (and non-hyper-v physicals).

Note: the WOL function in my script is taken from here: http://gallery.technet.microsoft.com/scriptcenter/Send-WOL-packet-using-0638be7b

5. Created a simple PowerShell module to execute the 2 steps I wrote.

On the jump server, I created a powershell module called “LabAdmin”, which contains 2 functions that simply execute the powershell script:

image

6. Configured port forwarding on my ADSL router to allow me to access the PSWA site from the Internet

This allows me to manage my lab even when I’m not home.

i.e. starting the lab via my mobile phone (over 4G):

image

Here are the live demos for both scripts:

Start-Lab:

Stop-Lab:

For your reference, the scripts can be downloaded HERE.

Conclusion

I live in Australia, one of the countries with the highest electricity prices. It is time for me to do something to cut down the running cost of my home lab – especially when my colleagues told me their average electricity bills are only half of mine.

Now, I can remotely start my entire lab anywhere via my mobile phone, and it only takes me a single command to shut down the lab, I won’t need to have them running 24×7. So I’m hoping my implemented this new feature in my lab, I should be able to see some noticeable reductions in my next power bill. :)

PowerShell Module to resize console – Updated

Written by Tao Yang

PSWAIcon Few days ago I wrote a PowerShell module that contains 1 cmdlet / function to resize the PowerShell console windows.

It was a quick job that I did less than half an hour. I wrote it primarily to make PowerShell Web Access (PSWA) more user friendly.

Over the last couple of days, I spent a bit more time on this module, and add a lot more functionality to it. The original module had 107 lines of code, and the updated one has 591 lines.

Here’s a list of new features:

Additional cmdlets

This module now contains the following cmdlets:

  • Resize-Console
  • Get-CurrentConsoleSize
  • Save-ConsoleProfile
  • Remove-ConsoleProfile
  • Get-ConsoleProfile
  • Update-ConsoleProfile

I’ll go through each cmdlets later

Aliases for all cmdlets and parameters

Since I wrote this module primarily for PSWA, and I intend to access PSWA primarily from mobile devices such as phones and tablets, I need to make the module easier to use. I am sure I’m not the only person who’s suffering from fat finger syndrome. I HATE typing on tablets and phones. Even with the Type Cover 2 for my Surface Pro 2, I found the keys are too small. So less is more, aliases really help when I use mobile devices because I don’t have to type as much.

Buffer width is always same as window width when re-sizing

When working on any kind of command prompts (cmd or PowerShell), I really don’t like the horizontal scroll bar. by making the buffer width always the same as window width, I don’t have to see the horizontal bars anymore.

Resize-Console –max switch

Or “rsc –m” if use aliases. The –max switch will move the window to the top left corner of the PRIMARY monitor and maximize the window size. It also set the buffer height to the maximum value of 9999. – This is equivalent to maximizing a normal window.

Every time I get on to a box (most likely via RDP) for the first time, I always had to manually set the PowerShell console size to suit my needs. then next time I RDP in from another computer with different display resolutions, I often had to set it again.

With resize-console –max, it will always set the console to the maximum size and occupies the entire screen. It will make my life so much easier. Not that I have OCD(Obsessive Compulsive Disorder), but for those ones who do, this function would make you much happier I suppose :). I’ll demonstrate this in the Youtube video at the end of this article.

Note: for this functionality, I used some of the code from Richard Siddaways’s blog. So thanks to Richard.

Resize-Console –Profile

I have included a XML file (profiles.xml) in this module. We can save pre-defined console dimension (Window width and height) to this XML so we can use them later.

i.e.:

SNAGHTML1aca2b96

The screen size and resolution are different among different computers and mobile devices. I have created different profiles for each type of devices that I own, so when I use a particular device to access PSWA, I can simply apply the appropriate screen size to suit that device.

i.e. the screenshot below is taken from my mobile phone (Samsung Note3):

image

when I applied the profile “Note3”, the PSWA console fits perfectly on the screen.

Or, on my 10.1 inch tablet Samsung Galaxy Tab2:

image

I used aliases, applied the “tab2” profile to fit the screen.

With the introduction to the –profile functions, this module now includes these functions for CRUD operations:

  • Save-ConsoleProfile
  • Remove-ConsoleProfile
  • Get-ConsoleProfile
  • Update-ConsoleProfile

For details of each functions, You can refer to the help information (get-help)

Note: only administrators will be able to modify the profiles.xml because it’s located in a system folder. so if UAC is enabled, admins will need launch powershell console as Administrator in order to use the Remove-ConsoleProfile and Update-ConsoleProfile cmdlet.

Get-CurrentConsoleSize

This one simply display the current window size and buffer size on screen. it’s reading the properties of “$host.ui.rawui”

SNAGHTML1ad77daf[4]

For your reference, here’s a recorded demo that I have updated to Youtube:

Please watch this video in full screen and 720P/1080P or you may not be able to see what’s happening on the powershell console.

You can download the module HERE. simply unzip and copy the whole folder to C:\Windows\System32\WindowsPowerShell\v1.0\Modules

So why am I spending time on this PowerShell project rather than System Center, which is my bread and butter? That would be the topic for my next blog article. :)

Please feel free to contact me for any issues or suggestions.

Until next time, happy PowerShelling :)

PowerShell Module: Resize-Console

Written by Tao Yang

I’m currently working on a solution that relies on PowerShell Web Access (Hopefully I can finish tonight and blog it in next couple of days).

I have been a bit hesitate to use use PWSA every since I firstly tried it out briefly back in 2012 (and blogged my experience here).

Why am I hesitated? this is why:

image

The interface is just not that user-friendly with such a small window and that much useless space. There is no way to easily resize the window.

In my original blog post, I posted a simple script to increase the size. Today, I spent a little bit more time, wrote a module based on the original code, and of course made it more flexible.

This module has only one function called Resize-Console:


Function Resize-Console
{
<#  .Synopsis Resize PowerShell console window .Description Resize PowerShell console window. Make it bigger, smaller or increase / reduce the width and height by a specified number .Parameter -Bigger Increase the window's both width and height by 10. .Parameter -Smaller Reduce the window's both width and height by 10. .Parameter Width Resize the window's width by passing in an integer. .Parameter Height Resize the window's height by passing in an integer. .Example # Make the window bigger. Resize-Console -bigger  .Example # Make the window smaller. Resize-Console -smaller  .Example # Increase the width by 15. Resize-Console -Width 15  .Example # Reduce the Height by 10. Resize-Console -Height -10  .Example # Reduce the Width by 5 and Increase Height by 10. Resize-Console -Width -5 -Height 10 #>

[CmdletBinding()]
PARAM (
[Parameter(Mandatory=$false,HelpMessage="Increase Width and Height by 10")][Switch] $Bigger,
[Parameter(Mandatory=$false,HelpMessage="Reduce Width and Height by 10")][Switch] $Smaller,
[Parameter(Mandatory=$false,HelpMessage="Increase / Reduce Width" )][Int32] $Width,
[Parameter(Mandatory=$false,HelpMessage="Increase / Reduce Height" )][Int32] $Height
)

#Get Current Buffer Size and Window Size
$bufferSize = $Host.UI.RawUI.BufferSize
$WindowSize = $host.UI.RawUI.WindowSize
If ($Bigger -and $Smaller)
{
Write-Error "Please make up your mind, you can't go bigger and smaller at the same time!"
} else {
if ($Bigger)
{
$NewWindowWidth = $WindowSize.Width + 10
$NewWindowHeight = $WindowSize.Height + 10

#Buffer size cannot be smaller than Window size
If ($bufferSize.Width -lt $NewWindowWidth)
{
$bufferSize.Width = $NewWindowWidth
}
if ($bufferSize.Height -lt $NewWindowHeight)
{
$bufferSize.Height = $NewWindowHeight
}
$WindowSize.Width = $NewWindowWidth
$WindowSize.Height = $NewWindowHeight

} elseif ($Smaller)
{
$NewWindowWidth = $WindowSize.Width - 10
$NewWindowHeight = $WindowSize.Height - 10
$WindowSize.Width = $NewWindowWidth
$WindowSize.Height = $NewWindowHeight
}

if ($Width)
{
#Resize Width
$NewWindowWidth = $WindowSize.Width + $Width
If ($bufferSize.Width -lt $NewWindowWidth)
{
$bufferSize.Width = $NewWindowWidth
}
$WindowSize.Width = $NewWindowWidth
}
if ($Height)
{
#Resize Height
$NewWindowHeight = $WindowSize.Height + $Height
If ($bufferSize.Height -lt $NewWindowHeight)
{
$bufferSize.Height = $NewWindowHeight
}
$WindowSize.Height = $NewWindowHeight

}
#commit resize
$host.UI.RawUI.BufferSize = $buffersize
$host.UI.RawUI.WindowSize = $WindowSize
}

}

image

I have copied the folder containing this module to C:\Windows\System32\PowerShell\v1.0\Modules folder on the server hosting PSWA site so it is available for everyone.

Here’s a screen video capture if you want to see it in action:

Note: Please watch this video in full screen (by double-clicking the video) and choose 720P if you can. Otherwise you might not see much in such a small window.

This module also works on normal PowerShell prompt windows. You can download this PSConsole module HERE. to set it up, simply copy to the folder I mentioned above.

Few PowerShell One-Liners To Check WinRM Settings on Remote Machines

Written by Tao Yang

To Check if WinRM has been enabled on a Remote machine:

$RemoteMachine = “Remote Machine Name”

[system.convert]::ToBoolean(((winrm get winrm/config/winrs -r:$remotemachine | ?{$_ -imatch "AllowRemoteShellAccess"}).split("="))[1].trim())

To Check the Default HTTP listener port on a remote machine:

$RemoteMachine = “Remote Machine Name”

[System.Convert]:: ToInt32(((winrm get winrm/config/Service/DefaultPorts -r:$RemoteMachine | ?{$_ -imatch "HTTP = " }).split("="))[1].trim())

To Check the Default HTTPS listener port on a remote machine:

$RemoteMachine = “Remote Machine Name”

[System.Convert]:: ToInt32(((winrm get winrm/config/Service/DefaultPorts -r:$RemoteMachine | ?{$_ -imatch "HTTPS = " }).split("="))[1].trim())

image

Finding OpsMgr Management Group Installation Date Using PowerShell

Written by Tao Yang

As part of what I’m working on at the moment, I need to find out when the OpsMgr 2012 management group was initially installed using PowerShell (the installation time of the first management server).

To do so, I can either use the OpsMgr SDK or the OperationsManager PowerShell module. I’ve developed below scripts to run locally on a management server:

Using SDK:

$MgmtServer = $Env:COMPUTERNAME
#Connect to SCOM management group
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.EnterpriseManagement.OperationsManager.Common") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.EnterpriseManagement.OperationsManager") | Out-Null
$MGConnSetting = New-Object Microsoft.EnterpriseManagement.ManagementGroupConnectionSettings($MgmtServer)
$MG = New-Object Microsoft.EnterpriseManagement.ManagementGroup($MGConnSetting)
$MG.GetManagementGroupMonitoringObject()

TimeAdded property indicates the MG initial installation date.

image

Using OperationsManager PowerShell module:

import-module OperationsManager
$mg = Get-SCOMManagementGroup
$mg.GetManagementGroupMonitoringObject() | format-list

image

Using SCOM 2012 SDK to Retrieve Resource Pools Information

Written by Tao Yang

Today I needed to retrieve information about SCOM 2012 resource pools in a PowerShell script, I needed to do this directly via SDK, rather than using the OperationsManager PowerShell module. I couldn’t find any existing scripts via Google, so I spent some time playing with SDK and finally found it. Since it seems no one has mentioned it on the web, here’s how I did it:

Firstly, load the SDK DLL’s. I always use below function:

function Load-SDK()
{
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.EnterpriseManagement.OperationsManager.Common") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.EnterpriseManagement.OperationsManager") | Out-Null
}

Load-SDK

Secondly, connect to the management group. Since I’ll be running this script on a management server, I’m connecting to the management group via the SDK service on the local machine:

$MGConnSetting = New-Object Microsoft.EnterpriseManagement.ManagementGroupConnectionSettings($env:computername)
$MG = New-Object Microsoft.EnterpriseManagement.ManagementGroup($MGConnSetting)

Then, get the management group administration

$Admin = $MG.Administration

Finally, get all resource pools

$ResourcePools = $admin.GetManagementServicePools()

image

In the past, I’ve been using the GetAdministration() method from the management group object to retrieve MG administration object. This time, When I did it, the MG administration object returned from the method does not contain a method for GetManagementServicePools. I then realised the management group contains a property called Administration. the object type is the same as what’s returned from GetAdministration() method.

image

But it looks like the object returned from the “Administration” property contains more members:

image

This is just a quick observation. In the future, I’ll remember to check both places.

My First Impression on PowerShell Web Access

Written by Tao Yang
PSWA

I ran up an instance of Windows Server 2012 in my test lab last night so I can play with various new features such as IPAM and PowerShell Web Access, etc.

Today I configured this box as the PowerShell Web Access (PSWA) gateway. I have to say, I am very very impressed! The implementation is easy, took me less than an hour (including time spent reading TechNet articles) and having ability to access PowerShell console on virtually any web browser for all Windows machines in my lab is just fantastic!

Now I can probably get away from using RDP most of the times since I’m pretty comfortable with PowerShell Smile

So, here are the steps I took to setup PSWA:

1. Add the PSWA feature in Server Manager

2. Install PSWA web application using PowerShell:

Install-PswaWebApplication

3. Requested and installed a SSL certificate for the PSWA gateway machine from my Enterprise CA

4. In IIS, configured HTTPS for the default web site and used the SSL certificate I just installed from previous step.

5. Created an AD group called PSWA_Users and added few user IDs into this group.

6. Create PSWA Authorization Rule:

Add-PSWAAuthorizationRule -UserGroupName Corp\PSWA_Users -Computername * -ConfigurationName *

image

7. Since I can’t guarantee that WinRM has been enabled and configured on every machine, I’ve created a GPO to enable WinRM and linked it to the domain root.

Now, PSWA is pretty much ready to go. I launch the web access console on Google Chrome and entered my credential and the computer that I wish to connect to:

image

And I’m in!

image

It’s great to see that Microsoft releases a web-based product that runs on browsers other than IE. I don’t think I’ve seen anything like this before!

Additional Configurations:

I started testing by connecting to a SCOM management server and tried to retrieve all SCOM agents in my management group (Only 11 in total so I’d assume not huge amount of data is returned). I used:

Import-Module OperationsManager

$a = Get-SCOMAgent

Interestingly, it failed and the connection to the management server was closed:

image

Error:

Processing data for a remote command failed with the following error message: The WSMan provider host process did not return a proper response. A provider in the host process may have behaved improperly.

This reminded me the default setting for “Maximum amount of memory in MB per Shell” for WinRM, which I blogged previously in this post. The default setting on Windows Server 2008 R2 and Windows 7 is 150MB. This default setting has increased to 1024MB on Windows Server 2012 and Windows 8.

So to test, since I have 3 management servers in the OM12 management group, I’ve increased this setting to 1024 on another management server. It fixed the error:

image

To further prove this error is actually caused by not having enough memory for the remote shell, I’ve connected PSWA to a Windows 8 machine, which has OM12 console and command shell installed. I used the following commands to connect to the OM12 management group:

Import-Module OperationsManager

New-SCManagementGroupConnection OpsMgrMS03

It prompted an error saying I don’t have sufficient permission:

image

This is by design, when using second hop in CredSSP, the credential has to be explicitly specified. so I changed the command to:

New-SCManagementGroupConnection OpsMgrMS03 –Credential (Get-Credential domain\MyID)

after entering the password, I was successfully connected and I managed to retrieve all SCOM agents by using Get-SCOMAgent Cmdlet without issues.

image

So to fix this issue once for all, I’ve modified the GPO I’ve just created and changed the “Maximum amount of memory in MB per Shell” setting to 1024.

Click here to see settings defined in my WinRM GPO.

I also configured another port forwarding rule on my ADSL router to forward port 443 to the PSWA gateway computer so I can connect when I’m not home.

PSWA on Mobile Devices:

I am able to launch and use PSWA on both my Android tablet (Samsung Galaxy Tab 10.1v running ICS) and my wife’s iPad 3 (running iOS 6) using both built-in browsers and Google Chrome on both devices.

Below are few screenshots from my Galaxy Tab:

image

image

Maybe it’s just me being an Apple noob, when I’m on the iPad, I could not find the Tab key on the keyboard, so I couldn’t use the PowerShell auto completion feature. – One more reason that I’m staying away from that product!

Console Size:

by default, the console size is 120×35, which seems like a waste of space when I’m on a big screen.

So I wrote a simple PowerShell script called Resize-Console.ps1 to resize the window:

$bufferSize = $Host.UI.RawUI.BufferSize
$buffersize.Width = 180
$host.UI.RawUI.BufferSize = $buffersize

$WindowSize = $host.UI.RawUI.WindowSize
$WindowSize.Width = 180
$WindowSize.Height = 40
$host.UI.RawUI.WindowSize = $WindowSize

After I ran this script, the console fits perfectly on my Galaxy tab (resolution 1280×800):

image

This console size also works great on my laptop, which has the resolution of 1366×768. For different resolutions, the width and height need to be adjusted in the script. the only catch is the buffersize cannot be less than the window size (I set the width for both sizes to be the same).

I haven’t managed to work out a automated way to resize the console as when in a PS remote session, there is no $profile so I can’t add scripts into $profile like we normally do on a local console. If I find a way in the future, I’ll post it here.

This is what I found so far. I’ll continue to blog on this topic if I find any other interesting stuff!

By the way, I followed this TechNet article to configure the PSWA: Deploy Windows PowerShell Web Access

PowerShell Script To Enable SCOM Agent Proxy in a More Efficient Way

Written by Tao Yang

if you search on how to enable SCOM agent proxy for all your SCOM agents using PowerShell, you’ll get lots of posts and scripts that shows you how to do it in SCOM 2007 or 2012. In fact, I have written few back in the days.

However, no matter if the script uses SCOM 2007 PowerShell Snap-in, or SCOM 2012 PowerShell module, or even SCOM SDK, there is one limitation: the “ProxyingEnabled” property of the agent class is not one of the search criteria that you can use when retrieving the agent:

image

If you use the SCOM SDK, there are only 4 property names that can be used in the search criteria expression:

  • Id
  • Name
  • LastModified
  • DisplayName

ref: http://msdn.microsoft.com/en-us/library/microsoft.enterprisemanagement.administration.agentmanagedcomputercriteria.aspx

So in order to retrieve the agents that are not ProxyingEnabled, we can only client-side filtering, which retrieves ALL agents in the management group and then filter-out the ones that ProxyingEnabled is set to False.

i.e.

Using SCOM 2007 PowerShell Snap-in:

Get-agent | where-object {$_.ProxyingEnabled -match "false"}| foreach {$_.ProxyingEnabled = $true; $_.applyChanges()}

Using SCOM 2012 PowerShell Module:

Get-SCOMAgent | where-object {$_.ProxyingEnabled –match “false”} | Enable-SCOMAgentProxy

Using SCOM SDK in PowerShell:

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.EnterpriseManagement.OperationsManager.Common") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.EnterpriseManagement.OperationsManager") | Out-Null

$RMS = “RMS SERVER NAME”

$MGConnSetting = New-Object Microsoft.EnterpriseManagement.ManagementGroupConnectionSettings(RMS )
$MG = New-Object Microsoft.EnterpriseManagement.ManagementGroup($MGConnSetting)

#Get MG Admin
$Admin = $MG.GetAdministration()

#Search agents
$Agents = $Admin.GetAllAgentManagedComputers()
Foreach ($Agent in $Agents)
{
If (!($Agent.ProxyingEnabled.Value))
{
Write-Host "Enabling Agent Proxy for $($Agent.Name)`..."
$Agent.ProxyingEnabled = $true
$Agent.ApplyChanges()

}
}

Imagine in a large management group with few thousands agents or more and there are only couple of agents that don’t have Agent Proxy enabled. the script / cmdlet will take a long time and a lot of system resources to run because it needs to retrieve information of ALL agents first!

So I wrote a PowerShell script to perform this task a bit differently:

  1. Firstly run a SQL query against SCOM operational database to retrieve a list of agents that do not have agent proxy enabled
  2. connect to SCOM SDK and for each agent retrieved from the database, turn on agent proxy.

This is much more efficient as it only retrieves agents that do not have agent proxy enabled, not the whole lot!

The script uses SCOM SDK, it works on both 2007 and 2012 environments.

Syntax:

To run it on a SCOM management server, no other parameters need to be specified.

image

To run it on a SCOM agent, you will need to specify a management server in the management group that you wish to connect to (does not have to be RMS or RMSE)

image

Additionally, the default SQL query timeout is set to 120 seconds, you can specify a different value by using the –SQLQueryTimeout parameter

image

DOWNLOAD Enable-AgentProxy.ps1

By the way, I also tried to run below SQL command to directly change the ProxyingEnabled attribute in the database (similar to Kevin Holman’s query to change all agents to remote manageable):

Update MT_HealthService Set ProxyingEnabled = 1 where ProxyingEnabled = 0

After I ran this SQL command, the agent proxy setting did get updated in the SCOM console, but I’m not sure if this is supported or not, thus I wrote this script instead.

PowerShell Function: Get-WeekDayInMonth

Written by Tao Yang

Often, IT admins need to workout the first/second/third/fourth Mon/Tue/Wed/Thur/Fri/Sat/Sun of any given month. some good examples are:

  • Prepare themselves for Microsoft’s patching Tuesday of each month
  • Planning for any admin tasks caused by Day Light Saving time change

So I wrote this simple function today to calculate the date for any given month & year.

Here’s the function:

Function Get-WeekDayInMonth ([int]$Month, [int]$year, [int]$WeekNumber, [int]$WeekDay)
{

$FirstDayOfMonth = Get-Date -Year $year -Month $Month -Day 1 -Hour 0 -Minute 0 -Second 0
#First week day of the month (i.e. first monday of the month)
[int]$FirstDayofMonthDay = $FirstDayOfMonth.DayOfWeek
$Difference = $WeekDay - $FirstDayofMonthDay
If ($Difference -lt 0)
{
$DaysToAdd = 7 - ($FirstDayofMonthDay - $WeekDay)
} elseif ($difference -eq 0 )
{
$DaysToAdd = 0
}else {
$DaysToAdd = $Difference
}
$FirstWeekDayofMonth = $FirstDayOfMonth.AddDays($DaysToAdd)
Remove-Variable DaysToAdd
#Add Weeks
$DaysToAdd = ($WeekNumber -1)*7
$TheDay = $FirstWeekDayofMonth.AddDays($DaysToAdd)
If (!($TheDay.Month -eq $Month -and $TheDay.Year -eq $Year))
{
$TheDay = $null
}
$TheDay
}

the $weekday variable represents the week day you after:

0 Sunday
1 Monday
2 Tuesday
3 Wednesday
4 Thursday
5 Friday
6 Saturday
Usage:
Example #1: to query the 2nd Tuesday of October 2012:
Get-WeekDayInMonth –month 10 –year 2012 –Weeknumber 2 –Weeday 2
OR
Get-WeekDayInMonth 10 2012 2 2
image
Example #2: to query the 1st Sunday of May 2013:
Get-WeekDayInMonth –month 5 –year 2013 –Weeknumber 1 –Weeday 0
OR
Get-WeekDayInMonth 5 2013 1 0

image