#Powershell Service Uptime

So i wanted to see how long a couple of BlackBerry servers had been up, but I wanted to know how long the services has been running.  So i knocked this up.  Its dead simple to change for other services!

$Servers = "BES01", "BES02"
$Matrix = @()
ForEach($Server in $Servers){
  Write-Host $Server -Foregroundcolor Green
  $SVC = Get-Service -ComputerName $Server | Where {$_.Name -like "Black*"}
  Foreach($item in $SVC){
    $tmpMatrix="" | Select Server, Service, State, Uptime
    Write-Host "-" $Item.Name
    $tmpMatrix.Server = $Server
    $tmpMatrix.Service = $item.Name
    $s = gwmi win32_service -ComputerName $Server -filter "name = ‘$($item.Name)’"
    $tmpMatrix.State = $s.State
    If ($s.State -eq "Running"){
      $tmpUpTime = "{0}" -f ((get-date) – ([wmi]”).ConvertToDateTime((gwmi Win32_Process  -ComputerName $Server -filter "ProcessID = ‘$($s.ProcessId)’").CreationDate))
      $tmpMatrix.Uptime = $tmpUpTime
    }
    $Matrix += $tmpMatrix
  }
}
  $Matrix

Get-DatabaseDistribution.ps1

#msexchange #powershell

How cr@p am I? I totally forgot about this baby.  So this is rough and ready Disappointed smile not had a chance to sort the help out at the beginning, but I’m sure you will get the idea.  Basically run this with one of the switches ByMailboxSize or ByMailboxCount and it will look at your exchange 2010 mailboxes and try and load balance the users.  It doesn’t actually DO anything, what it will do is generate a CSV that you use as input for Move-RequestFromCSV that is here: http://flaphead.dns2go.com/?p=2945

Let me know what you think.  In the test I have done so far ByMailboxCount is shweet, ByMailboxSize isn’t perfect.  Enjoy

PARAM([String]$Database="", [String]$BatchName, [Switch]$ByMailboxCount, [Switch]$ByMailboxSize, [String]$SizePercentage=2, [String]$ExportCSV="$pwdmiguserlist.csv")

#http://stackoverflow.com/questions/5863772/powershell-round-down-to-nearest-whole-number
function round( $value, [MidpointRounding]$mode = ‘AwayFromZero’ ) {   [Math]::Round( $value, $mode ) }

#$DB=@();Get-MailboxDatabase * | ForEach{$db += $_.name}

$xPsCheck = Get-PSSnapin | Select Name | Where {$_.Name -Like "*Exchange*"}
If ($xPsCheck -eq $Null) {Add-PsSnapin Microsoft.Exchange.Management.PowerShell.e2010}

Write-Host "Database:……."$Database
Write-Host "ByMailboxCount:."$ByMailboxCount
Write-Host "ByMailboxSize:.."$ByMailboxSize
Write-Host "SizePercentage:."$SizePercentage
Write-Host "ExportCSV:……"$ExportCSV
Write-Host ""

If ($Database -ne ""){
  $tmpDatabaseArray = $database.split(" ")
  $i=0
  $DatabaseHashTable = @{}
  ForEach($item in $tmpDatabaseArray){; $DatabaseHashTable.Add($i,$item); $i++}
}

$tmpDatabaseArray

$MailboxArray=@()
ForEach($item in $tmpDatabaseArray){
  Write-Host "`nChecking Database" $item -Foregroundcolor Green
  $position=$host.ui.rawui.cursorposition
  $tmpMailbox = Get-Mailbox -Database $item -ResultSize unlimited
  $mbxcnt   = 0
  $mbxItems = 0
  $mbxSize  = 0
  ForEach($xMailbox in $tmpMailbox){
    $tmpUser = $xmailbox.PrimarySmtpAddress.toString()
    $host.ui.rawui.cursorposition=$position;
    Write-Host "-" $tmpuser "                                                                          "
    $tmpMailboxArray = "" | Select DisplayName, Email, ServerName, Database, Items, Size, Target, Status 
    $tmpMailboxArray.DisplayName = $xMailbox.DisplayName
    $tmpMailboxArray.Email       = $tmpUser
    $tmpMailboxArray.ServerName  = $xMailbox.ServerName
    $tmpMailboxArray.Database    = $xMailbox.Database
    $tmpMailboxArray.Target      = $xMailbox.Database
    $tmpMailboxStatistics        = Get-Mailbox $tmpUser | Get-MailboxStatistics
    $tmpMailboxArray.Items       = $tmpMailboxStatistics.ItemCount
    $tmpMailboxArray.Size        = $tmpMailboxStatistics.TotalItemSize.Value.ToMB()
    $MailboxArray += $tmpMailboxArray
    $mbxcnt ++
    $mbxItems += $tmpMailboxArray.Items
    $mbxSize  += $tmpMailboxArray.Size
  }
  $host.ui.rawui.cursorposition=$position;
  Write-Host "-> Complete! " -NoNewLIne
  Write-Host $mbxcnt -NoNewLine -ForegroundColor Yellow
  Write-Host " Mailboxes Found with " -NoNewline
  Write-Host $mbxItems -NoNewLine -ForegroundColor Yellow
  Write-host " Items and " -NoNewLine
  Write-Host $mbxSize -ForegroundColor Yellow -NoNewLine
  Write-Host "MB            "
}

#Okay lets count the number of databases
$DatabaseCount = $tmpdatabasearray.count
$MailboxCount  = $MailboxArray.count
$MailboxSize   = ($MailboxArray | Measure-Object Size -sum).Sum
$MailboxesPerDatabase = round ($MailboxCount / $DatabaseCount )
$MBPerDatabase = round ($MailboxSize / $DatabaseCount )

Write-Host "Database Count:……………."$DatabaseCount
Write-Host "Mailbox Count:…………….."$MailboxCount
Write-Host "Ideal Mailboxes Per Database:.."$MailboxesPerDatabase
Write-Host "Total Size:……………….."$MailboxSize
Write-Host "Ideal MB Per Database:………"$MBPerDatabase
$MBPerDatabase = round ($MBPerDatabase + (($MBPerDatabase /100)*$SizePercentage))
Write-Host "`nMB Per Database (+"$SizePercentage"%) = "$MBPerDatabase

#Group MailboxArray by Database
$DatabaseCountArray = $MailboxArray | Group Database
$DatabaseMatrix = @()
ForEach($Item in $DatabaseCountArray){
  $tmpDatabaseMatrix = "" | Select Name, Count, Difference1, Difference2, MB , Difference3, Difference4
  $tmpDatabaseMatrix.Name        = $Item.Name
  $tmpDatabaseMatrix.Count       = $Item.Count
  $tmpDatabaseMatrix.Difference1 = $MailboxesPerDatabase – $Item.Count
  $tmpDatabaseMatrix.Difference2 = $Item.Count – $MailboxesPerDatabase
  $tmpDatabaseMatrix.MB    &#160
;     = ($Item.Group | Measure-Object Size -Sum).Sum
  $tmpDatabaseMatrix.Difference3 = $MBPerDatabase – $tmpDatabaseMatrix.MB
  $tmpDatabaseMatrix.Difference4 = $tmpDatabaseMatrix.MB – $MBPerDatabase

  $DatabaseMatrix += $tmpDatabaseMatrix
}
$DatabaseMatrix | ft

If ($ByMailboxSize){
  Write-Host "`nBY MAILBOX SIZE" -Foregroundcolor Red
  Write-Host "—————"
  Write-Host "`nFinding databases with excess mailboxes"
  $Database2MoveOff = $DatabaseMatrix | Where {$_.Difference4 -ge 0}
  ForEach($db in $Database2MoveOff){
    Write-Host $db.Name -Foregroundcolor Blue
    $tmpExcess = $MailboxArray | where {$_.Database -eq $db.Name} | Sort Size -Descending
    $targetMB=0
    ForEach($yUser in $MailboxArray | where {$_.Database -eq $db.Name} | Sort Size -Descending){
      $tmpMB = $yUser.Size
      If ($tmpMB + $targetMB -gt $MBPerDatabase){
        $yUser.Target = ""
      } ELSE {
        $yuser.Status = "Keep"
        $targetMB += $tmpMB
      } #If ($tmpMB + $targetMB -gt $MBPerDatabase)
    } #ForEach $yUser
  } #ForEach $db

  Write-Host "`nAssigning excess mailboxes"
  ForEach($item in $DatabaseMatrix | Where {$_.Difference3 -gt 0}){
    $Mailboxes2Move =  $DatabaseMatrix | Where {$_.Target -eq ""}  
    $targetMB=$item.MB
    ForEach($yUser in $MailboxArray | where {$_.Target -eq ""} | Sort Size -Descending){
      $tmpMB = $yUser.Size
      If ($tmpMB + $targetMB -gt $MBPerDatabase){
        $yUser.Target = ""
      } ELSE {
        $yuser.Target = $item.Name
        $yuser.Status = "Move"
        $targetMB += $tmpMB
      } #If ($tmpMB + $targetMB -gt $MBPerDatabase)
    } #ForEach $yUser
  } #ForEach $item

  Write-Host "`nSUMMARY" -Foregroundcolor Green
  Write-Host "Ideal MB Per Database:………"$MBPerDatabase
  $MailboxArray | Group Target | %{
    New-Object psobject -Property @{
        Item = $_.Name
        Sum = ($_.Group | Measure-Object Size -Sum).Sum
    }
  }
} #If ($ByMailboxSize)

If ($ByMailboxCount){
  Write-Host "`nBY MAILBOX COUNT" -Foregroundcolor Red
  Write-Host "—————-"
  Write-Host "Check to see if the Excess Mailboxes = Required " -NoNewLine
  $tmpcheck = ($DatabaseMatrix | Measure-Object Difference1 -Sum).sum
  Write-Host $tmpcheck -ForegroundColor Green

  Write-Host "`nFinding databases with excess mailboxes"
  $Database2MoveOff = $DatabaseMatrix | Where {$_.Difference2 -ge 0}
  $ExcessTotal = 0
  ForEach($db in $Database2MoveOff){
    Write-Host $db.Name -Foregroundcolor Blue
    Write-Host "Removing"$db.Difference2 "users`n"
    $ExcessTotal += $db.Difference2
    $MailboxArray | Where {$_.Database.Name -eq $db.name} | Select -First $db.Difference2 | ForEach{$_.Target = "";$_.Status = "Move"}
  }

  Write-Host "Total Excess Mailbox " $ExcessTotal
  $i=0
  ForEach($item in $DatabaseMatrix | Where {$_.Difference1 -gt 0}){
    $Mailboxes2Add = $item.Difference1
    $MailboxArray | Where {$_.Target -eq ""} | Select -First $Mailboxes2Add | ForEach{$_.Target = $item.Name}
  }

  Write-Host "`nSUMMARY" -Foregroundcolor Green
  $MailboxArray | Group Target
}#ByMailboxCount

#Foreach($line in $MailboxArray){Write-Host $line.Email"`t"$line.database}

Write-Host "`nMove Mailboxes"
$outCSV = @()
$ExcessMailboxes = $MailboxArray | where {$_.Status -eq "Move"}

ForEach($item in $ExcessMailboxes){
  $tmpOutCsv                = "" | Select email, TargetDatabase
  $tmpOutCSV.email          = $item.email
  $tmpOutCsv.TargetDatabase = $Item.Target
  $outCSV += $tmpOutCSV
}

ForEach($line in $outCSV){
  $position=$host.ui.rawui.cursorposition
  Write-Host $line.email
  $position.x = 50
  $host.ui.rawui.cursorposition=$position;
  Write-host $line.target
}
$outCSV | Export-csv $ExportCSV -NoTypeInformation

Get-LyncServer v1.3

#Powershell, #Lync

Wow feedback .. thanks mike for the observation on the vertical text.  Have updated it to do it a different way, so let me know what you think.

You can download it here or cut and paste below

<#
  .NOTES
  NAME: Get-LyncServer.ps1
  AUTHOR: Paul Flaherty
  Last Edit: "v1.3 [28 February 2012]

  v1.0 08 Feb 2012 : A script it born
  v1.1 20 Feb 2012 : Change Services to *RTC* instead of RTC*
  v1.2 21 Feb 2012 : Added Lync Server version
  v1.3 28 Feb 2012 : Updated HTML TH style

  .LINK
  blogs.flaphead.com

  .SYNOPSIS
  This Script gets connectes to a Lync Server and enumerates a list
  of all OCS/Lync Servers and gathers additional information.
.DESCRIPTION
  This script will connect to a Lync Server using the /OcsPowershell URI.
  Once connected it will use Get-CsComputer to get a list of OCS/Lync related servers.
  Then it uses Get-CsService to get a list of Lync Services and the Lync related
  windows services.

  The script then creates a matrix of the data an output a CSV file and HTML web Page
.OUTPUTS
  Get-LyncServer.html
  Get-LyncServer.csv
.EXAMPLE
  Get-LyncServer.ps1
  This will prompt you for Credentials and search the AD for a lync server to use
.EXAMPLE
  Get-LyncServer.ps1 -LyncServer myLyncServer01
  This will prompt you for Credentials and use the specified lync server.
  it will also add the default ad domain to the server name is missing
.EXAMPLE
  Get-LyncServer.ps1 -CredentialsFile .creds.txt
  This will search the AD for a lync server to use and use the current user account and
  credentials store in the CredentialsFile as the password
.EXAMPLE
  Get-LyncServer.ps1 -CredentialsFile .creds.txt -LyncServer myLyncServer01
  This will use the specified lync server and use the current user account and
  credentials store in the CredentialsFile as the password
  .PARAMETER LyncServer
  Netbios or FQDN of a lync server to use.
  If the Netbios name is used, the AD Domain DNS name will be appended
  .PARAMETER CredentialsFile
  Credentials Password file for the current logged on user.
  To Create the credentials file run:
  $creds = Get-Credential
  $creds.Password  | ConvertFrom-SecureString | Set-Content creds.txt

#>
##########################################################################################
PARAM([String]$LyncServer="", [String]$CredentialsFile="")

$AppName                = "Get-LyncServer.ps1"
$AppVer                 = "v1.3 [28 February 2012]"
$errorPref              = $errorActionPreference
$errorActionPreference  = "SilentlyContinue"
$ServerName             = hostname
$Today                  = Get-Date
$Global:CurrentUser     = [System.Security.Principal.WindowsIdentity]::GetCurrent()
$Global:CurrentUserName = $Global:CurrentUser.Name
$xUser                  = $Global:CurrentUserName
$currentdom             = [System.DirectoryServices.ActiveDirectory.Domain]::getcurrentdomain()
$Forest                 = $currentdom.Forest.ToString()
$ForestDomain           = $Forest
$xHTMLoutFolder         = "E:PsMon.LyncHTML"

##########################################################################################
#Display script name and version
#########################################################################################
Write-host " " $AppName -NoNewLine -foregroundcolor Green
Write-Host ": " $AppVer -foregroundcolor Green
Write-host "`n Run on $ServerName at $Today by $xUser" -foregroundcolor Yellow
Write-Host "|——————————————————————-|`n"
##########################################################################################
#Load the Lync bits & bobs
#########################################################################################
If($CredentialsFile -eq "") {
  $creds = Get-Credential -Credential $xUser
}ELSE{
  Write-Host "Using Credentials for " -NoNewLine
  Write-Host $xUser -NoNewLine -ForeGroundColor Yellow
  Write-Host " and password from " -NoNewLine
  Write-Host $CredentialsFile -ForeGroundColor Yellow

  $password = Get-Content $CredentialsFile | ConvertTo-SecureString
  $creds = New-Object System.Management.Automation.PsCredential $xUser,$password
} #$CredentialsFile

If($LyncServer -eq ""){
  Write-Host "Looking in RTCHSUniversalServices for a Lync Server"
  $Forest              = $Forest.Replace(".", ",DC=")
  $Forest              = "DC=" + $Forest
  $Dom                 = "LDAP://"
  $Dom                += $Forest
  $Root                = New-Object DirectoryServices.DirectoryEntry $Dom
  $Filter              = "(&(ObjectCategory=group)(name=*RTCHSUniversalServices*))"
  $selector            =
New-Object DirectoryServices.DirectorySearcher $Filter
  $selector.PageSize   = 1000
  $selector.SearchRoot = $root
  $objs                = $selector.findall()
  $tmpGroup            = $objs | Select Path -First 1
  $Group               = [ADSI]$tmpGroup.Path
  $GrpMembers          = $Group.Member
  $grpCnt              = $GrpMembers.Count
  Write-Host "Found Group.  It has " -NoNewLine
  Write-Host  $GrpCnt -NoNewLine -ForeGroundColor Green
  Write-Host " Members"

  $LyncServerList = @()
  ForEach($tmpMember in $GrpMembers){
    $tmpADSI = "LDAP://" + $tmpMember
    $tmpA    = [ADSI]$tmpADSI
    If($tmpA.objectClass -contains "computer"){$LyncServerList += $tmpA.Name}
  }

  $LyncServerList = $LyncServerList | Sort
  $tmpNumber = Get-Random -Minimum 0 -Maximum $LyncServerList.Count
  $LyncServer = $LyncServerList[$tmpNumber]
  $LyncServer = $LyncServer + "." + $ForestDomain
  $LyncConnectionURI = "
https://" + $LyncServer + "/OcsPowershell" 

 

}ELSE{
  IF($LyncServer.Contains(".") -eq $False){$LyncServer = $LyncServer + "." + $ForestDomain}
  $LyncConnectionURI = "
https://" + $LyncServer + "/OcsPowershell"
}

Write-Host "`nConnecting to:"$LyncConnectionURI
$s=New-PSSession -ConnectionURI $LyncConnectionURI -Credential $creds
If ($s -eq $Null){
  Write-Host "Error connecting to Lync" -Foregroundcolor Red
  Write-Host "Exiting" -Foregroundcolor Yellow
  Exit
}
Import-PSSession $s

$arrObjects = @()
$LyncRoleLabels = @()
$LyncRoleLabels += "Computer", "Pool", "Site", "ProductVersion", "DeploymentType", "OS", "RAM","UpToDate"

Write-Host "`nGetting Lync Servers`t" -NoNewLine
$LyncServers  = Get-CsComputer | Sort Identity
Write-host $LyncServers.Count"`n" -ForeGroundColor Green

Write-Host "Get-CsService`t" -NoNewLine
$LyncService  = Get-CsService
Write-Host $LyncService.count "Services found" -ForeGroundColor Green

Write-Host "`nGetting Windows Services"
$LyncWindowsServices = @()
ForEach($item in $LyncServers){
  $n = $item.Identity
  Write-Host $n"`t" -NoNewLine
  $tmpLWS = @()
  $tmpLWS = Get-Service *RTC* -ComputerName $n #| select @{Expression={($_.DisplayName).Replace(" ","")};Label="DisplayName"}, Status
  Write-Host $tmpLWS.count -ForeGroundColor Green
  $LyncWindowsServices += $tmpLWS

 
}
Write-host "Total Services Found"$LyncWindowsServices.count

$LyncWindowsServicesByServer = $LyncWindowsServices | Group MachineName

#Get Available Roles
Write-host "`nGetting Lync Server Roles"

$LyncRoles = $LyncService | group Role | sort name
ForEach($tmpRole in $LyncRoles){$LyncRoleLabels += $tmpRole.Name}
$LyncServiceByPool = $LyncService | Group PoolFqdn | Sort Name

#Get Available Services
$grpLyncWindowsServices = $LyncWindowsServices | Group DisplayName
$grpLyncWindowsServices | ForEach{$n = $_.name; $LyncRoleLabels += $n}

Write-Host "`nMatrix Label Count" $LyncRoleLabels.count
Write-Debug $LyncRoleLabels

Write-Host "`nBuilding Matrix"
ForEach($tmpServer in $LyncServers){
  $tmpLyncServerId = $tmpServer.Identity
  Write-Host $tmpLyncServerId
  $objSite = Get-CsPool -Identity $tmpServer.pool | Select-Object Site
  $objReplication = $Null
  $objReplication = Get-CsManagementStoreReplicationStatus -ReplicaFqdn $tmpLyncServerId | Select-Object UpToDate
  $strReplication = $objSite.site -replace("Site:","")
  $tmpOS          = Get-WmiObject win32_operatingsystem -ComputerName $tmpLyncServerId

  $key="SOFTWAREMicrosoftReal-Time Communications"
  $type = [Microsoft.Win32.RegistryHive]::LocalMachine
  $regKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($type, $tmpLyncServerId)
  $regKey = $regKey.OpenSubKey($key, $True)
  $tmpLabel = $regKey.GetValueNames()
  $tmpVC = "" | Select $tmpLabel
  ForEach($vc in $regKey.GetValueNames()){$tmpVC.$vc = $regkey.GetValue($vc)}

  $tmpLyncServer = "" | Select $LyncRoleLabels
  $tmpLyncServer.Computer = $tmpLyncServerId
  $tmpLyncServer.Pool     = $tmpServer.Pool
  $tmpLyncServer.Site     = $strReplication
  $tmpLyncServer.UpToDate = $objReplication.UpToDate
  $tmpLyncServer.OS       = $tmpOS.Caption + " " + $tmpOS.CSDVersion
  $tmpLyncServer.RAM      = "!AR!" + $tmpOS.FreePhysicalMemory
  $tmpLyncServer.ProductVersion = $tmpVC.ProductVersion
  $tmpLyncServer.DeploymentType = $tmpVC.DeploymentType

  $tmpLSbP = $LyncServiceByPool | Where {$_
.Name -eq $tmpLyncServerId}
  ForEach($item in $tmpLSbP){
    $tmpG = $item.Group
    ForEach($itemG in $tmpG){
      $xRole = $itemG.Role
      $tmpLyncServer.$xRole = $True
    }
  }

  $tmpWinSvc = $LyncWindowsServicesByServer | Where {$_.Name -eq $tmpLyncServerId}
  ForEach($item in $tmpWinSvc){
    $tmpG = $item.Group
    Write-Host $tmpG.count  
    ForEach($itemG in $tmpG){
      $xSvc = $itemG.DisplayName
      Write-Host $xSvc
      $tmpLyncServer.$xSvc = "svc"
    }
  }

  $arrObjects += $tmpLyncServer
}

$HtmlHeader = "
<Style>
  TABLE{border-width: 1px;
        padding: 1px;
        border-style: solid;
        border-color: black;
        border-collapse: collapse;}
  TD{border-width: 1px;
     padding: 1px;
     border-style: solid;
     border-color: black;}
  TH{font-family:’Arial’;
     font-size:12px;
     border-width: 1px;
     padding: 1px;
     border-style: solid;
     border-color: black;
     background-color:peachpuff;
     white-space: nowrap;
     writing-mode:tb-rl;
     filter: flipv fliph;
     Text-align:left}
  TR{font-family:’Arial’;
     font-size:10px}
  P{font-family:’Arial’;}
</Style>
<TITLE>LYNC SERVERS</TITLE>"

$z="<B><FONT size=’2′ face=’VERDANA’>Lync Servers</B></FONT><BR><FONT size=’1′ face=’VERDANA’>Last updated: $today</FONT></font><HR size=6 color=Green>"
$xHTML = $arrObjects | ConvertTo-Html -head $HtmlHeader -Title "Lync Server Info" -body $z

$txtYELLOW = @()
$txtAR     = @()
$i=0; $xHTML | foreach{IF ($_ -like "*<td>True*"){ $txtYellow += $i}; $i++}
$txtYELLOW | ForEach{$xHTML[$_] = $xHTML[$_].Replace("<td>True","<td bgcolor=ORANGE>True")}

$txtYELLOW = @()
$i=0; $xHTML | foreach{IF ($_ -like "*<td>svc*"){ $txtYellow += $i}; $i++}
$txtYELLOW | ForEach{$xHTML[$_] = $xHTML[$_].Replace("<td>svc","<td bgcolor=ORANGE>svc")}

$i=0; $xHTML | foreach{IF ($_ -like "*>!AR!*"){ $txtAR += $i;}; $i++}
$txtAR | ForEach{$xHTML[$_] = $xHTML[$_].Replace(">!AR!"," align=right>")}

$xEnd = get-Date
$xHTML += "
<HR size=6 color=Green>
<FONT size=’1′ face=’VERDANA’>Script Completed: $xEnd</FONT>
</FONT><BR></BODY>
</HTML>
"

$arrObjects | ForEach{$_.RAM = $_.RAM.Replace("!AR!","")}
$xHTML      | out-file $xHTMLoutFolderGet-LyncServer.html
$arrObjects | Export-csv Get-LyncServer.csv -NoTypeInformation

Get-PSSession | ForEach{Remove-PSSession -id $_.id}
$errorActionPreference = $errorPref
#End
##########################################################################################

Get-LyncServer v1.2

#Powershell, #Lync

Okay so made some updates to include Lync/OCS version, Lync Type, OS and Memory.  Also change the services from RTC* to *RTC*

Downloadable from here or cut and paste below .. enjoy

<#
  .NOTES
  NAME: Get-LyncServer.ps1
  AUTHOR: Paul Flaherty
  Last Edit: "v1.2 [21 February 2012]
  .LINK
  blogs.flaphead.com
  .SYNOPSIS
  This Script gets connectes to a Lync Server and enumerates a list
  of all OCS/Lync Servers and gathers additional information.
 .DESCRIPTION
  This script will connect to a Lync Server using the /OcsPowershell URI.
  Once connected it will use Get-CsComputer to get a list of OCS/Lync related servers.
  Then it uses Get-CsService to get a list of Lync Services and the Lync related
  windows services.

  The script then creates a matrix of the data an output a CSV file and HTML web Page
 .OUTPUTS
  Get-LyncServer.html
  Get-LyncServer.csv
 .EXAMPLE
  Get-LyncServer.ps1
  This will prompt you for Credentials and search the AD for a lync server to use
 .EXAMPLE
  Get-LyncServer.ps1 -LyncServer myLyncServer01
  This will prompt you for Credentials and use the specified lync server.
  it will also add the default ad domain to the server name is missing
 .EXAMPLE
  Get-LyncServer.ps1 -CredentialsFile .creds.txt
  This will search the AD for a lync server to use and use the current user account and
  credentials store in the CredentialsFile as the password
 .EXAMPLE
  Get-LyncServer.ps1 -CredentialsFile .creds.txt -LyncServer myLyncServer01
  This will use the specified lync server and use the current user account and
  credentials store in the CredentialsFile as the password
  .PARAMETER LyncServer
  Netbios or FQDN of a lync server to use.
  If the Netbios name is used, the AD Domain DNS name will be appended
  .PARAMETER CredentialsFile
  Credentials Password file for the current logged on user.
  To Create the credentials file run:
  $creds = Get-Credential
  $creds.Password  | ConvertFrom-SecureString | Set-Content creds.txt

#>

PARAM([String]$LyncServer="", [String]$CredentialsFile="")
##########################################################################################
$AppName = "Get-LyncServer.ps1"
$AppVer  = "v1.0 [13 February 2012]"
#v1.0 08 Feb 2012 : A script it born
#v1.1 20 Feb 2012 : Change Services to *RTC* instead of RTC*
#v1.2 21 Feb 2012 : Added Lync Server version
#
# This script gets a list of Lync Servers
#
#Written By Paul Flaherty
#blogs.flaphead.com
##########################################################################################
$errorPref = $errorActionPreference
$errorActionPreference = "SilentlyContinue"

$ServerName             = hostname
$Today                  = Get-Date
$Global:CurrentUser     = [System.Security.Principal.WindowsIdentity]::GetCurrent()
$Global:CurrentUserName	= $Global:CurrentUser.Name
$xUser                  = $Global:CurrentUserName
$currentdom             = [System.DirectoryServices.ActiveDirectory.Domain]::getcurrentdomain()
$Forest                 = $currentdom.Forest.ToString()
$ForestDomain           = $Forest

$xHTMLoutFolder         = "E:PsMon.LyncHTML"

##########################################################################################
#Display script name and version
#########################################################################################
Write-host " " $AppName -NoNewLine -foregroundcolor Green
Write-Host ": " $AppVer -foregroundcolor Green
Write-host "`n Run on $ServerName at $Today by $xUser" -foregroundcolor Yellow
Write-Host "|-------------------------------------------------------------------|`n"
##########################################################################################
#Load the Lync bits & bobs
#########################################################################################
If($CredentialsFile -eq "") {
  $creds = Get-Credential -Credential $xUser
}ELSE{
  Write-Host "Using Credentials for " -NoNewLine
  Write-Host $xUser -NoNewLine -ForeGroundColor Yellow
  Write-Host " and password from " -NoNewLine
  Write-Host $CredentialsFile -ForeGroundColor Yellow

  $password = Get-Content $CredentialsFile | ConvertTo-SecureString
  $creds = New-Object System.Management.Automation.PsCredential $xUser,$password
} #$CredentialsFile

If($LyncServer -eq ""){
  Write-Host "Looking in RTCHSUniversalServices for a Lync Server"
  $Forest              = $Forest.Replace(".", ",DC=")
  $Forest              = "DC=" + $Forest
  $Dom                 = "LDAP://"
  $Dom                += $Forest
  $Root                = New-Object DirectoryServices.DirectoryEntry $Dom
  $Filter              = "(&(ObjectCategory=group)(name=*RTCHSUniversalServices*))"
  $selector            = New-Object DirectoryServices.DirectorySearcher $Filter
  $selector.PageSize   = 1000
  $selector.SearchRoot = $root
  $objs                = $selector.findall()
  $tmpGroup            = $objs | Select Path -First 1
  $Group               = [ADSI]$tmpGroup.Path
  $GrpMembers          = $Group.Member
  $grpCnt              = $GrpMembers.Count
  Write-Host "Found Group.  It has " -NoNewLine
  Write-Host  $GrpCnt -NoNewLine -ForeGroundColor Green
  Write-Host " Members"

  $LyncServerList = @()
  ForEach($tmpMember in $GrpMembers){
    $tmpADSI = "LDAP://" + $tmpMember
    $tmpA    = [ADSI]$tmpADSI
    If($tmpA.objectClass -contains "computer"){$LyncServerList += $tmpA.Name}
  }

  $LyncServerList = $LyncServerList | Sort
  $tmpNumber = Get-Random -Minimum 0 -Maximum $LyncServerList.Count
  $LyncServer = $LyncServerList[$tmpNumber]
  $LyncServer = $LyncServer + "." + $ForestDomain
  $LyncConnectionURI = "https://" + $LyncServer + "/OcsPowershell"



}ELSE{
  IF($LyncServer.Contains(".") -eq $False){$LyncServer = $LyncServer + "." + $ForestDomain}
  $LyncConnectionURI = "https://" + $LyncServer + "/OcsPowershell"
}

Write-Host "`nConnecting to:"$LyncConnectionURI
$s=New-PSSession -ConnectionURI $LyncConnectionURI -Credential $creds
If ($s -eq $Null){
  Write-Host "Error connecting to Lync" -Foregroundcolor Red
  Write-Host "Exiting" -Foregroundcolor Yellow
  Exit
}
Import-PSSession $s

$arrObjects = @()
$LyncRoleLabels = @()
$LyncRoleLabels += "Computer", "Pool", "Site", "ProductVersion", "DeploymentType", "OS", "RAM","UpToDate"

Write-Host "`nGetting Lync Servers`t" -NoNewLine
$LyncServers  = Get-CsComputer | Sort Identity
Write-host $LyncServers.Count"`n" -ForeGroundColor Green

Write-Host "Get-CsService`t" -NoNewLine
$LyncService  = Get-CsService
Write-Host $LyncService.count "Services found" -ForeGroundColor Green

Write-Host "`nGetting Windows Services"
$LyncWindowsServices = @()
ForEach($item in $LyncServers){
  $n = $item.Identity
  Write-Host $n"`t" -NoNewLine
  $tmpLWS = @()
  $tmpLWS = Get-Service *RTC* -ComputerName $n #| select @{Expression={($_.DisplayName).Replace(" ","")};Label="DisplayName"}, Status
  Write-Host $tmpLWS.count -ForeGroundColor Green
  $LyncWindowsServices += $tmpLWS


}
Write-host "Total Services Found"$LyncWindowsServices.count

$LyncWindowsServicesByServer = $LyncWindowsServices | Group MachineName

#Get Available Roles
Write-host "`nGetting Lync Server Roles"

$LyncRoles = $LyncService | group Role | sort name
ForEach($tmpRole in $LyncRoles){$LyncRoleLabels += $tmpRole.Name}
$LyncServiceByPool = $LyncService | Group PoolFqdn | Sort Name

#Get Available Services
$grpLyncWindowsServices = $LyncWindowsServices | Group DisplayName
$grpLyncWindowsServices | ForEach{$n = $_.name; $LyncRoleLabels += $n}

Write-Host "`nMatrix Label Count" $LyncRoleLabels.count
Write-Debug $LyncRoleLabels

Write-Host "`nBuilding Matrix"
ForEach($tmpServer in $LyncServers){
  $tmpLyncServerId = $tmpServer.Identity
  Write-Host $tmpLyncServerId
  $objSite = Get-CsPool -Identity $tmpServer.pool | Select-Object Site
  $objReplication = $Null
  $objReplication = Get-CsManagementStoreReplicationStatus -ReplicaFqdn $tmpLyncServerId | Select-Object UpToDate
  $strReplication = $objSite.site -replace("Site:","")
  $tmpOS          = Get-WmiObject win32_operatingsystem -ComputerName $tmpLyncServerId

  $key="SOFTWAREMicrosoftReal-Time Communications"
  $type = [Microsoft.Win32.RegistryHive]::LocalMachine
  $regKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($type, $tmpLyncServerId)
  $regKey = $regKey.OpenSubKey($key, $True)
  $tmpLabel = $regKey.GetValueNames()
  $tmpVC = "" | Select $tmpLabel
  ForEach($vc in $regKey.GetValueNames()){$tmpVC.$vc = $regkey.GetValue($vc)}


  $tmpLyncServer = "" | Select $LyncRoleLabels
  $tmpLyncServer.Computer = $tmpLyncServerId
  $tmpLyncServer.Pool     = $tmpServer.Pool
  $tmpLyncServer.Site     = $strReplication
  $tmpLyncServer.UpToDate = $objReplication.UpToDate
  $tmpLyncServer.OS       = $tmpOS.Caption + " " + $tmpOS.CSDVersion
  $tmpLyncServer.RAM      = "!AR!" + $tmpOS.FreePhysicalMemory
  $tmpLyncServer.ProductVersion = $tmpVC.ProductVersion
  $tmpLyncServer.DeploymentType = $tmpVC.DeploymentType

  $tmpLSbP = $LyncServiceByPool | Where {$_.Name -eq $tmpLyncServerId}
  ForEach($item in $tmpLSbP){
    $tmpG = $item.Group
    ForEach($itemG in $tmpG){
      $xRole = $itemG.Role
      $tmpLyncServer.$xRole = $True
    }
  }

  $tmpWinSvc = $LyncWindowsServicesByServer | Where {$_.Name -eq $tmpLyncServerId}
  ForEach($item in $tmpWinSvc){
    $tmpG = $item.Group
    Write-Host $tmpG.count
    ForEach($itemG in $tmpG){
      $xSvc = $itemG.DisplayName
      Write-Host $xSvc
      $tmpLyncServer.$xSvc = $True
    }
  }

  $arrObjects += $tmpLyncServer
}


$HtmlHeader = "
<Style>
  TABLE{border-width: 1px;padding: 1px;border-style: solid;border-color: black;border-collapse: collapse;}
  TD{border-width: 1px;padding: 1px;border-style: solid;border-color: black;}
  TH{font-family:'Arial';font-size:12px;border-width: 1px;padding: 1px;border-style: solid;border-color: black;background-color:peachpuff;layout-flow:vertical-ideographic;Text-align:left}
  TR{font-family:'Arial';font-size:10px}
  P{font-family:'Arial';}
</Style>
<TITLE>LYNC SERVERS</TITLE>"

$z="<B><FONT size='2' face='VERDANA'>Lync Servers</B></FONT><BR><FONT size='1' face='VERDANA'>Last updated: $today</FONT></font><HR size=6 color=Green>"
$xHTML = $arrObjects | ConvertTo-Html -head $HtmlHeader -Title "Lync Server Info" -body $z

$txtYELLOW = @()
$txtAR     = @()
$i=0; $xHTML | foreach{IF ($_ -like "*<td>True*"){ $txtYellow += $i}; $i++}
$txtYELLOW | ForEach{$xHTML[$_] = $xHTML[$_].Replace("<td>True","<td bgcolor=ORANGE>True")}

$i=0; $xHTML | foreach{IF ($_ -like "*>!AR!*"){ $txtAR += $i;}; $i++}
$txtAR | ForEach{$xHTML[$_] = $xHTML[$_].Replace(">!AR!"," align=right>")}


$xEnd = get-Date
$xHTML += "
<HR size=6 color=Green>
<FONT size='1' face='VERDANA'>Script Completed: $xEnd</FONT>
</FONT><BR></BODY>
</HTML>
"

$xHTML      | out-file $xHTMLoutFolderGet-LyncServer.html
$arrObjects | Export-csv Get-LyncServer.csv -NoTypeInformation

Get-PSSession | ForEach{Remove-PSSession -id $_.id}
$errorActionPreference = $errorPref
#End
##########################################################################################

Get-LyncServer v1

#Powershell, #Lync

So I just love Exchange 2010 and PowerShell, and a cmdlet that rocks is Get-ExchangeServer which is a cmdlet that get the attributes of some or all the servers in the Exchange organization.

Lync however doesn’t have a similar cmdlet and that annoyed the hell out of me.  All I want is a list of Lync Servers and what they do .. simple you would think! Think again Disappointed smile

So I knocked this up.  It has some help text too that will help with the usage.  You can run get-help ./get-lyncserver –full

The basic output is a HTML summary matrix and a csv file that I use as input to other scripts.  Essentially I run this script once a day and then the other scripts when needed.

Oh another thing, the connectionuri needs credentials .. help explains how to set them or you get a prompt.

Let me know what you think!  this is v1 to enjoy

You can download the script from here or copy and paste from here:

<#
  .NOTES
  NAME: Get-LyncServer.ps1
  AUTHOR: Paul Flaherty
  Last Edit: "v1.0 [13 February 2012]
  .LINK
  blogs.flaphead.com
  .SYNOPSIS
  This Script gets connects to a Lync Server and enumerates a list
  of all OCS/Lync Servers and gathers additional information.
 .DESCRIPTION
  This script will connect to a Lync Server using the /OcsPowershell URI.
  Once connected it will use Get-CsComputer to get a list of OCS/Lync related servers.
  Then it uses Get-CsService to get a list of Lync Services and the Lync related
  windows services.

  The script then creates a matrix of the data an output a CSV file and HTML web Page
 .OUTPUTS
  Get-LyncServer.html
  Get-LyncServer.csv
 .EXAMPLE
  Get-LyncServer.ps1
  This will prompt you for Credentials and search the AD for a lync server to use
 .EXAMPLE
  Get-LyncServer.ps1 -LyncServer myLyncServer01
  This will prompt you for Credentials and use the specified lync server.
  it will also add the default ad domain to the server name is missing
 .EXAMPLE
  Get-LyncServer.ps1 -CredentialsFile .creds.txt
  This will search the AD for a lync server to use and use the current user account and
  credentials store in the CredentialsFile as the password
 .EXAMPLE
  Get-LyncServer.ps1 -CredentialsFile .creds.txt -LyncServer myLyncServer01
  This will use the specified lync server and use the current user account and
  credentials store in the CredentialsFile as the password
  .PARAMETER LyncServer
  Netbios or FQDN of a lync server to use.
  If the Netbios name is used, the AD Domain DNS name will be appended
  .PARAMETER CredentialsFile
  Credentials Password file for the current logged on user.
  To Create the credentials file run:
  $creds = Get-Credential
  $creds.Password  | ConvertFrom-SecureString | Set-Content creds.txt

#>

PARAM([String]$LyncServer="", [String]$CredentialsFile="")
##########################################################################################
$AppName = "Get-LyncServer.ps1"
$AppVer  = "v1.0 [13 February 2012]"
#v1.0 08 Feb 2012 : A script it born
#
# This script gets a list of Lync Servers
#
#Written By Paul Flaherty
#blogs.flaphead.com
##########################################################################################
$errorPref = $errorActionPreference
$errorActionPreference = "SilentlyContinue"

$ServerName             = hostname
$Today                  = Get-Date
$Global:CurrentUser     = [System.Security.Principal.WindowsIdentity]::GetCurrent()
$Global:CurrentUserName	= $Global:CurrentUser.Name
$xUser                  = $Global:CurrentUserName
$currentdom             = [System.DirectoryServices.ActiveDirectory.Domain]::getcurrentdomain()
$Forest                 = $currentdom.Forest.ToString()
$ForestDomain           = $Forest

$xHTMLoutFolder         = $pwd

##########################################################################################
#Display script name and version
#########################################################################################
Write-host " " $AppName -NoNewLine -foregroundcolor Green
Write-Host ": " $AppVer -foregroundcolor Green
Write-host "`n Run on $ServerName at $Today by $xUser" -foregroundcolor Yellow
Write-Host "|-------------------------------------------------------------------|`n"
##########################################################################################
#Load the Lync bits & bobs
#########################################################################################
If($CredentialsFile -eq "") {
  $creds = Get-Credential -Credential $xUser
}ELSE{
  Write-Host "Using Credentials for " -NoNewLine
  Write-Host $xUser -NoNewLine -ForeGroundColor Yellow
  Write-Host " and password from " -NoNewLine
  Write-Host $CredentialsFile -ForeGroundColor Yellow

  $password = Get-Content $CredentialsFile | ConvertTo-SecureString
  $creds = New-Object System.Management.Automation.PsCredential $xUser,$password
} #$CredentialsFile

If($LyncServer -eq ""){
  Write-Host "Looking in RTCHSUniversalServices for a Lync Server"
  $Forest              = $Forest.Replace(".", ",DC=")
  $Forest              = "DC=" + $Forest
  $Dom                 = "LDAP://"
  $Dom                += $Forest
  $Root                = New-Object DirectoryServices.DirectoryEntry $Dom
  $Filter              = "(&(ObjectCategory=group)(name=*RTCHSUniversalServices*))"
  $selector            = New-Object DirectoryServices.DirectorySearcher $Filter
  $selector.PageSize   = 1000
  $selector.SearchRoot = $root
  $objs                = $selector.findall()
  $tmpGroup            = $objs | Select Path -First 1
  $Group               = [ADSI]$tmpGroup.Path
  $GrpMembers          = $Group.Member
  $grpCnt              = $GrpMembers.Count
  Write-Host "Found Group.  It has " -NoNewLine
  Write-Host  $GrpCnt -NoNewLine -ForeGroundColor Green
  Write-Host " Members"

  $LyncServerList = @()
  ForEach($tmpMember in $GrpMembers){
    $tmpADSI = "LDAP://" + $tmpMember
    $tmpA    = [ADSI]$tmpADSI
    If($tmpA.objectClass -contains "computer"){$LyncServerList += $tmpA.Name}
  }

  $LyncServerList = $LyncServerList | Sort
  $tmpNumber = Get-Random -Minimum 0 -Maximum $LyncServerList.Count
  $LyncServer = $LyncServerList[$tmpNumber]
  $LyncServer = $LyncServer + "." + $ForestDomain
  $LyncConnectionURI = "https://" + $LyncServer + "/OcsPowershell"



}ELSE{
  IF($LyncServer.Contains(".") -eq $False){$LyncServer = $LyncServer + "." + $ForestDomain}
  $LyncConnectionURI = "https://" + $LyncServer + "/OcsPowershell"
}

Write-Host "`nConnecting to:"$LyncConnectionURI
$s=New-PSSession -ConnectionURI $LyncConnectionURI -Credential $creds
If ($s -eq $Null){
  Write-Host "Error connecting to Lync" -Foregroundcolor Red
  Write-Host "Exiting" -Foregroundcolor Yellow
  Exit
}
Import-PSSession $s

$arrObjects = @()
$LyncRoleLabels = @()
$LyncRoleLabels += "Computer", "Pool", "Site", "UpToDate"

Write-Host "`nGetting Lync Servers`t" -NoNewLine
$LyncServers  = Get-CsComputer | Sort Identity
Write-host $LyncServers.Count"`n" -ForeGroundColor Green

Write-Host "Get-CsService`t" -NoNewLine
$LyncService  = Get-CsService
Write-Host $LyncService.count "Services found" -ForeGroundColor Green

Write-Host "`nGetting Windows Services"
$LyncWindowsServices = @()
ForEach($item in $LyncServers){
  $n = $item.Identity
  Write-Host $n"`t" -NoNewLine
  $tmpLWS = @()
  $tmpLWS = Get-Service RTC* -ComputerName $n #| select @{Expression={($_.DisplayName).Replace(" ","")};Label="DisplayName"}, Status
  Write-Host $tmpLWS.count -ForeGroundColor Green
  $LyncWindowsServices += $tmpLWS
}
Write-host "Total Services Found"$LyncWindowsServices.count

$LyncWindowsServicesByServer = $LyncWindowsServices | Group MachineName

#Get Available Roles
Write-host "`nGetting Lync Server Roles"

$LyncRoles = $LyncService | group Role | sort name
ForEach($tmpRole in $LyncRoles){$LyncRoleLabels += $tmpRole.Name}
$LyncServiceByPool = $LyncService | Group PoolFqdn | Sort Name

#Get Available Services
$grpLyncWindowsServices = $LyncWindowsServices | Group DisplayName
$grpLyncWindowsServices | ForEach{$n = $_.name; $LyncRoleLabels += $n}

Write-Host "`nMatrix Label Count" $LyncRoleLabels.count
Write-Debug $LyncRoleLabels

Write-Host "`nBuilding Matrix"
ForEach($tmpServer in $LyncServers){
  $tmpLyncServerId = $tmpServer.Identity
  Write-Host $tmpLyncServerId
  $objSite = Get-CsPool -Identity $tmpServer.pool | Select-Object Site
  $objReplication = $Null
  $objReplication = Get-CsManagementStoreReplicationStatus -ReplicaFqdn $tmpLyncServerId | Select-Object UpToDate
  $strReplication = $objSite.site -replace("Site:","")

  $tmpLyncServer = "" | Select $LyncRoleLabels
  $tmpLyncServer.Computer = $tmpLyncServerId
  $tmpLyncServer.Pool     = $tmpServer.Pool
  $tmpLyncServer.Site     = $strReplication
  $tmpLyncServer.UpToDate = $objReplication.UpToDate

  $tmpLSbP = $LyncServiceByPool | Where {$_.Name -eq $tmpLyncServerId}
  ForEach($item in $tmpLSbP){
    $tmpG = $item.Group
    ForEach($itemG in $tmpG){
      $xRole = $itemG.Role
      $tmpLyncServer.$xRole = $True
    }
  }

  $tmpWinSvc = $LyncWindowsServicesByServer | Where {$_.Name -eq $tmpLyncServerId}
  ForEach($item in $tmpWinSvc){
    $tmpG = $item.Group
    Write-Host $tmpG.count
    ForEach($itemG in $tmpG){
      $xSvc = $itemG.DisplayName
      Write-Host $xSvc
      $tmpLyncServer.$xSvc = $True
    }
  }

  $arrObjects += $tmpLyncServer
}


$HtmlHeader = "
<Style>
  TABLE{border-width: 1px;padding: 1px;border-style: solid;border-color: black;border-collapse: collapse;}
  TD{border-width: 1px;padding: 1px;border-style: solid;border-color: black;}
  TH{font-family:'Arial';font-size:12px;border-width: 1px;padding: 1px;border-style: solid;border-color: black;background-color:peachpuff;layout-flow:vertical-ideographic;Text-align:left}
  TR{font-family:'Arial';font-size:10px}
  P{font-family:'Arial';}
</Style>
<TITLE>LYNC SERVERS</TITLE>"

$z="<B><FONT size='2' face='VERDANA'>Lync Servers</B></FONT><BR><FONT size='1' face='VERDANA'>Last updated: $today</FONT></font><HR size=6 color=Green>"
$xHTML = $arrObjects | ConvertTo-Html -head $HtmlHeader -Title "Lync Server Info" -body $z

$txtYELLOW = @()
$i=0; $xHTML | foreach{IF ($_ -like "*<td>True*"){ $txtYellow += $i}; $i++}
$txtYELLOW | ForEach{$xHTML[$_] = $xHTML[$_].Replace("<td>True","<td bgcolor=ORANGE>True")}


$xEnd = get-Date
$xHTML += "
<HR size=6 color=Green>
<FONT size='1' face='VERDANA'>Script Completed: $xEnd</FONT>
</FONT><BR></BODY>
</HTML>
"

$xHTML      | out-file $xHTMLoutFolderGet-LyncServer.html
$arrObjects | Export-csv Get-LyncServer.csv -NoTypeInformation

Get-PSSession | ForEach{Remove-PSSession -id $_.id}
$errorActionPreference = $errorPref
#End
##########################################################################################

Dump-RBAC.ps1

#Exchange #Exchange2010 #Powershell

So I have been meaning to post this for a while, so here it is.  I have a need to dump out the RBAC permissions for Exchange 2010 so I could see who had what.  So here is is.  The output is a HTML file.  You will need to create a folder called C:ps for it save it to.

Enjoy .. feedback welcome Winking smile

 

$Error.Clear()
#########################################################################################
$AppName = "Dump-RBAC.ps1"
$AppVer  = "v1.0 [4th Feburary 20111]"
#
#v1.0  05 Aug 2011 : A Script is born

#This script exports relevant RBAC information and generate a webpage
##########################################################################################

##########################################################################################
#Load the Exchange 2010 bits & bobs
#########################################################################################
$xPsCheck = Get-PSSnapin | Select Name | Where {$_.Name -Like "*Exchange*"}
If ($xPsCheck -eq $Null) {Add-PsSnapin Microsoft.Exchange.Management.PowerShell.e2010}

##########################################################################################
#Display script name and version
#########################################################################################
Write-host " " $AppName -NoNewLine -foregroundcolor Green
Write-Host ": " $AppVer -foregroundcolor Green
Write-host "`n Run on $ServerName at $Today by $xUser" -foregroundcolor Yellow
Write-Host "|——————————————————————-|`n"
Write-host "Log Folder: $DateFolder"

$RBACArray      = @()
$RBACCmd        = @()
$RoleGroupArray = @()

$tmpCols = Get-ManagementRoleAssignment
$tmpCols | group RoleAssigneeName | sort name | Select Name | ForEach{$feName = $_.Name; $feName = $feName.Replace(" ","");$xHTML += "<td>" + $fename + "</td>"}

$x=@();$x+="RoleName"; $tmpCols | group RoleAssigneeName | sort name | Select Name | ForEach{$feName = $_.Name; $feName = $feName.Replace(" ","");$x += $fename}

$tmpgmr = Get-ManagementRole | Sort Name
Write-Host "Getting Management Role Information"
ForEach($tmpRole in $tmpgmr){
  $tmpName = $tmpRole.Name
  Write-Host $tmpName
  $tmpArray = "" | Select $x
  $tmpCmd   = "" | Select RoleName, Commands

  ($tmpRole).RoleEntries | ForEach {$tmpcmd.Commands += $_.Name + " | "}

  $tmparray.RoleName = $tmpName #$_.Role
  $tmpCmd.RoleName   = $tmpName

  $gmra = $tmpCols | where {$_.Role -eq "$TmpName"}
  $gmra | sort RoleAssigneeName | ForEacH{$yy = $_.RoleAssigneeName;
    $yy = $yy.Replace(" ","")
    $tmparray.$yy = "x"
  }
  $RBACArray += $tmpArray
  $RBACCmd   += $tmpcmd
}

$tmpRoleGroups = $tmpCols | Where {$_.RoleAssigneeType -eq "RoleGroup"} | Group RoleAssigneeName | Select Name | Sort Name
$tmpRoleGroups | ForEach{
  $tmpmem = ""
  $tmpRG = "" | Select Name, Members
  $tmpRG.Name = $_.Name
  $tmpRG.Name
  $tmpGroup = Get-Group $tmpRG.Name
  $tmpGroupMembers = $tmpGroup.Members
  $tmpGroupMembers | ForEach{$tmpRG.Members += $_.Name + " | "}
  $RoleGroupArray += $tmpRG
}

$today = Get-Date
$HtmlHeader = "
<Style>
  TABLE{border-width: 1px;padding: 1px;border-style: solid;border-color: black;border-collapse: collapse;}
  TD{border-width: 1px;padding: 1px;border-style: solid;border-color: black;}
  TH{font-family:’Arial’;font-size:12px;border-width: 1px;padding: 1px;border-style: solid;border-color: black;background-color:peachpuff;layout-flow:vertical-ideographic;Text-align:left}
  TR{font-family:’Arial’;font-size:10px}
  P{font-family:’Arial’;}
</Style>
<TITLE>Exchange Server 2010 RBAC</TITLE>"
$z="<B><FONT size=’2′ face=’VERDANA’>Exchange Server 2010 RBAC Information</B></FONT><BR><FONT size=’1′ face=’VERDANA’>Last updated: $today</FONT></font><HR size=6 color=Green>"
$xhtml = $RBACArray | ConvertTo-Html -head $HtmlHeader  -Title "Exchange Server 2010 RBAC" -body $z -PreContent "<FONT size=’2′ face=’VERDANA’>"

$txtYELLOW = @()
$i=0; $xHTML | foreach{IF ($_ -like "*<td>x</td>*"){ $txtYELLOW += $i}; $i++}
$txtYELLOW | ForEach{$xHTML[$_] = $xHTML[$_].Replace("<td>x</td>","<td bgcolor=Yellow align=center><B>x</B></td>")}

$xHTML += "<HR>"
$xHTML += $RBACCmd | ConvertTo-Html -Fragment

$xHTML += "<HR>"
$xHTML += $RoleGroupArray  | ConvertTo-Html -Fragment

$xhtml | out-file c:psrbac.html

Get-RegistryValue

#Powershell

So I have been messing with Powershell for a while now, Jeff asked me to look at script he had that read remote registry values.  He was using PSRemoteRegistry but got some errors.

So I knocked this function up for him Winking smile

function Get-RegistryValue([Switch]$Recurse=$false, [String]$ComputerName=(hostname), [String]$Hive="HKLM", [String]$key)
{
  $OutArray = @()
  Switch($Hive){
    "HKCR"  {$type = [Microsoft.Win32.RegistryHive]::ClassesRoot}
    "HKU"   {$type = [Microsoft.Win32.RegistryHive]::Users}
    "HKPD"  {$type = [Microsoft.Win32.RegistryHive]::PerformanceData}
    "HKDD"  {$type = [Microsoft.Win32.RegistryHive]::DynData}
    "HKCU"  {$type = [Microsoft.Win32.RegistryHive]::CurrentUser}
    "HKLM"  {$type = [Microsoft.Win32.RegistryHive]::LocalMachine}
  }#Case

  $regKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($type, $ComputerName)
  $regKey = $regKey.OpenSubKey($key)
  If($regKey -eq $Null){Write-Host "Registry Key ["$Hive""$key"] Not Found" -ForeGroundColor Red;Return}
  Write-Host "`n"$regkey -ForeGroundColor Blue
  If ($Recurse -AND $regKey.SubKeyCount -gt 0){

    ForEach($sub in $regKey.GetSubKeyNames()){
      $SUBkey = $key + "" + $Sub
      Get-RegistryValue -ComputerName $ComputerName -Hive $Hive -Key $SUBKey -Recurse $Recurse
    }#ForEach
  }#If
  ForEach($Subx in $RegKey.GetValueNames()){
    $RegArray = "" | Select ComputerName, Key, Value, path
    $RegArray.ComputerName = $ComputerName
    $RegArray.Key          = $SubX
    $RegArray.Value        = $Regkey.GetValue($SubX)
    $RegArray.Path         = $RegKey.Name
    $OutArray             += $RegArray
  }#ForEach
Return $OutArray
}#End Function Get-RegistryValue

Essentially all you need to do is

Get-RegistryValue –ComputerName <Computername> -Key "SYSTEMCurrentControlSetservicesSNMPParametersTrapConfiguration" -Hive HKLM –Recurse

You change the -Hive switch to the particular registry hive (by default it will use HKLM), give it a computername (by default it will use the localhost) and a registry key path .. Done!

You can also recurse a registry if there are subkeys .. nice Open-mouthed smile

Let me know what you think

Enumerate-Groups.ps1

#Powershell #Exchange2010

I just wanted to share this cmdlet I created today.  I had a need to workout from Nested Groups including DDL’s the number of users a DL would reach, so I knocked this baby up.

Its v1, so any feedback is very welcome.  Usage is basically

Enumerate-Groups.ps1 –GroupName “Group”

or

Get-Group “Group” | ForEach{.Enumerate-Groups.ps1 –GroupName $_.DistinguishedName }

Enjoy

 

PARAM([String]$GroupName="",[Switch]$ShowUsers=$False, [String]$DomainController="<DC NAME>")

If($GroupName -eq ""){Write-Host "You need to specify a group";Exit}

##########################################################################################

$AppName = "Enumerate-Groups.ps1"

$AppVer  = "v1.0 [19 December2011]"

#v1.0 19 Dec 2011 : A script it born

#

# This script take a groupname as an agrument and then attempts to enumerate the users

# contained in the group by checking all necessary nested groups

#

#Parameters:

#GroupName        : Name of the group (top level) that you want to enumerate

#ShowUsers        : Displays and exports userlist to CSV

#DomainController : Name of a DC to use

#

#Written By Paul Flaherty

#blogs.flaphead.com 

##########################################################################################

#Display script name and version

#########################################################################################

Write-host " " $AppName -NoNewLine -foregroundcolor Green

Write-Host ": " $AppVer -foregroundcolor Green

Write-host "`n Run on $ServerName at $Today by $xUser" -foregroundcolor Yellow

Write-Host "|——————————————————————-|`n"

##########################################################################################

#Load the Exchange 2010 bits & bobs

#########################################################################################

$xPsCheck = Get-PSSnapin | Select Name | Where {$_.Name -Like "*Exchange*"}

If ($xPsCheck -eq $Null) {Add-PsSnapin Microsoft.Exchange.Management.PowerShell.e2010}

Import-Module ActiveDirectory

Function Enumerate-Group($InGroup){

  $tmpADo = Get-AdObject $InGroup  -Server $script:dc

  $tmpADo.ObjectClass

  If($tmpADo.ObjectClass -ne "msExchDynamicDistributionList"){

    $tmpExGroup = Get-Group $InGroup -resultsize 1 -DomainController $Script:DC

    $tmpGroup = Get-ADGroup $tmpExGroup.DistinguishedName -Properties Members  -Server $script:dc

    Write-Host "-"$tmpGroup.Name":"$tmpGroup.ObjectClass

    Write-host "+- Member Count: " $tmpGroup.Members.Count

    $Members = $tmpGroup.Members | Sort

    ForEach($Item in $Members){

      $tmpMember = Get-AdObject $Item  -Server $script:dc

      $tmpName   = $tmpMember.Name

      If($tmpMember.ObjectClass -ne "user"){

        Write-Host "+–" $tmpName":" $tmpMember.ObjectClass

      }

      $tmpUsers = "" | Select Name, DDL

      If($tmpMember.ObjectClass -eq "user"){

        $tmpUsers.Name = $tmpMember.name

        $tmpUsers.DDL  = $tmpGroup.Name

        $Script:Users += $tmpUsers

      }#If user

      if($tmpMember.ObjectClass -eq "group"){Enumerate-group $tmpMember.Name}

      if($tmpMember.ObjectClass -eq "msExchDynamicDistributionList"){

        Enumerate-DDL $TmpMember.Name

      } #If msExchDynamicDistributionList

    } #ForEach

  }ELSE{

    Write-Host "-"$tmpADo.Name":"$tmpGroup.ObjectClass

    Enumerate-DDL $tmpADo.Name

  }#IF

} #Function Enumerate-Group

Function Enumerate-DDL($InDDL){

  $tmpDDL   = Get-DynamicDistributionGroup $InDDL -DomainController $Script:DC

  $mc = Measure-Command {$tmpRecp  = Get-Recipient -RecipientPreviewFilter $tmpDDL.RecipientFilter -OrganizationalUnit $tmpDDL.RecipientContainer -ResultSize Unlimited -DomainController $Script:DC}

  $tmpCount = 0

  ForEach($r in $tmpRecp){$tmpCount ++}

  Write-Host "+— User Count: " -NoNewLine

  Write-Host $tmpCount -ForeGroundColor Green -NoNewLine

  Write-Host " in" $mc.TotalSeconds "Seconds`n"

  ForEach($item in $tmpRecp){

    If ($Item.name -ne ""){

      $tmpUsers = "" | Select Name, DDL

      $tmpUsers.Name = $Item.name

      $tmpUsers.DDL  = $tmpDDL.Name

      $Script:Users += $tmpUsers

    }

  }#ForEach

}#Function Enumerate-DDL

$script:DC    = $DomainController

$Script:users = @()

Write-Host "Domain Controller:.. $script:dc"

Write-Host "Show Users:……… $ShowUsers"

$g = Get-ADObject $GroupName -Server $script:dc

If($g -eq $Null){Write-host "Problem with the group";Exit}ELSE{Enumerate-group $GroupName}

$totusers  = $script:Users.Count

$tmpusers  = $script:users | sort Name -Unique

$totuusers = $tmpusers.count

Write-Host "`nTotal Users: " -NoNewLine

Write-Host $totusers -Foregroundcolor Green

Write-Host "`nTotal Unique Users: " -NoNewLine

Write-Host $totuusers -Foregroundcolor Green

If($ShowUsers){

  Write-Host "`n`nUser List" -foregroundcolor blue

  Write-Host "- Exporting to GroupUserList.csv"

  $Script:Users | Export-CSV GroupUserList.csv -NoTypeInformation -Delimiter "|"

  $Script:Users | sort DDL, Name

}

#End

Who locked me out?

#powershell

So following on from my last post, once and AD account is locked out, who or what the hell done it!

Typically you start with the account lockout tool (http://www.microsoft.com/download/en/details.aspx?id=15201) which will tell you when and what DC locked the account.

Next thing to do is to check the Security Event log out on the DC that locked you out to see who or what locked you out.

I have been playing cat and mouse with this over the last few days, and knocked this little baby up

#Script Start

PARAM([String]$DC="", [String]$Time = "")
$xtime  = get-date $time
$xstart = $xtime.AddSeconds(-1)
$xEnd   = $xtime.AddSeconds(1)
Write-Host "DC:…. " $DC
Write-Host "Start:. " $xstart
Write-Host "End:… " $xend
Get-WinEvent -ComputerName $DC -FilterHashtable @{logname="Security"; id=4740; StartTime=$xstart; EndTime=$xEnd} | fl TimeCreated, Message

#Script End

Save the above as “get-lockout.ps1”,  I found get-winevent a shed load quicker than get-event

Usage:

.get-lockout.ps1  -DC <DC> -Time "12/09/2011 09:33:00"

enjoy

AD Account Lockout

#powershell

So whose great idea was it to force a password change on service accounts every 60 days? Bunch of donkeys!?!

Anyway, so if you AD account gets locked out, check this out.  On tried with Windows 2008R2

import-module activedirectory

Unlock-ADAccount <account> –Server <DC>

NB the DC needs to have the “Active Directory Web Service” started