LiquidObject

Manual SCOM client migration

Today I had the task of migrating a number of systems over to the SCOM 2012 server with the existing server being offline. Running the normal discovery fails to redirect the nodes over to the system because of a pair of registry entries still pointing to the old system. The below batch script can be run one at a time or via some automation method (Config Manager in my case) to mass-migrate nodes over to the new system.

@REG ADD "HKLM\SOFTWARE\Microsoft\Microsoft Operations Manager\3.0\Agent Management Groups\LiquidObject\Parent Health Services\0" /v "AuthenticationName" /d "SCOM-1.liquidobject.com" /f
@REG ADD "HKLM\SOFTWARE\Microsoft\Microsoft Operations Manager\3.0\Agent Management Groups\LiquidObject\Parent Health Services\0" /v "NetworkName" /d "SCOM-1.liquidobject.com" /f

@NET STOP HEALTHSERVICE
@NET START HEALTHSERVICE
, ,
December 28, 2012 at 2:12 pm Comments (0)

Exchange 2010 Holiday Calendar Loading

Within an organization I had need to bulk load behind the scenes a number of calendar items on all employee’s accounts. This script had multiple sources with the original idea coming from http://www.mikepfeiffer.net/2011/01/creating-calendar-items-with-powershell-and-the-ews-managed-api/

To get this working requires a few things.
1) Exchange 2010 with SP1 (currently running under SP2)
2) The Exchange EMS shell installed
3) The Exchange Web Services API to be installed (http://www.microsoft.com/en-us/download/details.aspx?id=28952)
4) Elevated permissions within the Exchange environment.

Beyond your normal administration rights is the requirement for the ability to Impersonate all users within the organization. Because of the level of access required to make these changes please verify with the organization that there are no legal issues with attempting this.

#Path to your holiday file
$inputfile = "D:\Data\HolidayCalendar2012-2013.csv"
#Path to the EWS DLL file
$Webservices = "C:\Program Files\Microsoft\Exchange\Web Services\1.2\Microsoft.Exchange.WebServices.dll"
#Where are the users
$baseOU = "OU=My Employees,DC=liquidobject,DC=com"

#Need to update each year
$myyears = "2012-2013"
$myuniquebody = "My Unique Calendar Automation Message" + $myyears
#The above body entry was the easiest way for users to see that the items were loaded by the IT department and also provides the one place where we can go back and modify/delete calendar entries later.

#If we need to run the once per year everyone run, set this to true
$YearlyRun = $false

#Testing mode options
$testmode = $false
$testuser = "Testuser99"

####################### End Options ########################

if(!(Get-Module | where {$_.Name -eq "ActiveDirectory"})){Import-Module ActiveDirectory}
if(!(Get-PSSnapin -Name "Microsoft.Exchange.Management.PowerShell.E2010" -ErrorAction SilentlyContinue)){Add-pssnapin Microsoft.Exchange.Management.PowerShell.E2010}
if(!(Get-PSSnapin -Name "Microsoft.Exchange.Management.PowerShell.support" -ErrorAction SilentlyContinue)){Add-pssnapin Microsoft.Exchange.Management.PowerShell.support}

if(!(Test-Path $Webservices))
{
    Write-Host "`n`nExchange Web Services API is required and is not installed`nhttp://www.microsoft.com/en-us/download/details.aspx?id=28952`n"
    Exit
}
if(!(Test-Path $inputfile))
{
    Write-Host "`n`nInput file of: $inputfile is missing, cannot proceed without this file.`n`n"
    Exit
}
Write-Host "`nEWS Web Services - Loading"
Add-Type -Path $Webservices
Write-Host "EWS Web Services API - Loaded`n"

function New-CalendarItem {
    [CmdletBinding()]
    param(
        [Parameter(Position=1, Mandatory=$true)]$CalendarUser,
        [Parameter(Position=2, Mandatory=$true)]$Subject,
        [Parameter(Position=3, Mandatory=$true)]$Date
        )
    
    $sid = (Get-ADUser -Identity $CalendarUser).SID
    $user = [ADSI]"LDAP://<SID=$sid>"
    $service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService -ArgumentList ([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP1)
    $service.AutodiscoverUrl($user.Properties.mail)
    
    $Impersonate = (Get-Mailbox -Identity $calendaruser).PrimarySMTPAddress
    $ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId -ArgumentList ([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress),$Impersonate
    $service.ImpersonatedUserId = $ImpersonatedUserId
    
    $appointment = New-Object Microsoft.Exchange.WebServices.Data.Appointment -ArgumentList $service
    $appointment.Subject = $Subject
    $startdate = Get-Date($Date)
    $appointment.Start = $startdate
    $enddate = (Get-Date($Date)).adddays(1)
    $appointment.End = $enddate
    $appointment.body = $myuniquebody 
    $appointment.LegacyFreeBusyStatus = "Free"
    $appointment.IsAllDayEvent = $true
    $appointment.IsReminderSet = $False
    $appointment.Save([Microsoft.Exchange.WebServices.Data.SendInvitationsMode]::SendToNone)
#    Write-Host "New Entry: " $CalendarUser " - " $Subject " - " $Date
    $appointment = $null
    sleep 0.3
}

$mydata = Import-Csv $inputfile
Write-Host "Preparing to process" $mydata.count "calendar entries`n"

#Everyone, we need this once per year
if($YearlyRun)
{
    $myusers = Get-ADuser -Filter {(mail -like "*") -and (ObjectClass -eq "user") -and (Enabled -eq $true)} -SearchBase $baseOU -Properties created | Select-Object samaccountname, created
}
else
{
    #Normally grab just the last 7 days of users for a weekly run.
    $mydays = (Get-Date).Adddays(-7)
    $myusers = Get-ADuser -Filter {(mail -like "*") -and (ObjectClass -eq "user") -and (Created -gt $mydays) -and (Enabled -eq $true)} -SearchBase $baseOU -Properties created | Select-Object samaccountname, created
}

#sorting for easy troubleshooting
$myusers = $myusers | Sort-Object samaccountname
#For testing lock to a single user
if($testmode)
{
    $myusers2 = @{"samAccountName"=$testuser}
}

$today = Get-Date
$mycount = $myusers.count
$currentpos = 1
foreach($i in $myusers)
{
    Write-Host "Loading $currentpos of $mycount for:" $i.samaccountname
    foreach($entry in $mydata)
    {
        if($today -lt $entry.date)
        {
            #Write-Host $entry.date " - " $entry.Subject
            New-CalendarItem -CalendarUser $i.samaccountname -Subject $entry.Subject -date $entry.date
            sleep 0.2
        }
        else
        {
            if($YearlyRun) #only load past dates on the yearly run
            {
                New-CalendarItem -CalendarUser $i.samaccountname -Subject $entry.Subject -date $entry.date
                sleep 0.2
            }
        }
        
        sleep 0.1
    }
    $currentpos++
    sleep 1.5
}

All items created are all-day events with availability as as free with no reminders to annoy the staff. This is designed for an annual run and then adjustment of the “$YearlyRun” variable for weekly loads on all new employees.

The CSV file is in the following form:
Subject,Date
New Years Day, 2013/1/1
April Fools, 2013/4/1

Be careful on the characters used in the Subject entries as extra ” or ‘ characters can cause lots of headaches.

, ,
December 27, 2012 at 4:14 pm Comments (0)

Current Exchange CAS user counts

Below you’ll find a slight modification to a post from Mike Pfeiffer on querying Exchange 2010 CAS servers to obtain the current count of OWA and RPC clients.

function Get-CASActiveUsers {
  [CmdletBinding()]
  param(
      [Parameter(Position=0, ValueFromPipelineByPropertyName=$true, Mandatory=$true)]
      [String[]]$Name
      )

  process {
    $Name | %{
      $RPC = Get-Counter "\MSExchange RpcClientAccess\User Count" -ComputerName $_
      $OWA = Get-Counter "\MSExchange OWA\Current Unique Users" -ComputerName $_
      New-Object PSObject -Property @{
        Server = $_
        "RPC Client Access" = $RPC.CounterSamples[0].CookedValue
        "Outlook Web App" = $OWA.CounterSamples[0].CookedValue
      }
    }
  }
}

Get-CASActiveUsers CAS-1,CAS-2,CAS-3
, , ,
December 10, 2012 at 3:49 pm Comments (0)