Audit Terminal Server Sessions

9 05 2012

A client of mine asked me to help them with auditing terminal server sessions or more importantly, who is remoting into servers, the day, time, source and destination.  From the help of a blog below, I was able to generate a script that is used during logons and logoffs of every domain joined server.  I created a GPO that used the script to capture this information and post it to a log file on a share.  Most companies use loopback processing for their Server GPO so you’ll need to make sure to lookout for that. 

Our intentions were then to take the log information and place it in a SQL database so we could run SQL RS against it.

Here is the website:

http://msmvps.com/blogs/kwsupport/archive/2005/02/24/36942.aspx

Here is the script, btw, this was a .cmd.  This is the logon script and you’ll want to create an exact copy except with Logoff at the end.

@REM Setups %date variable
@REM First parses month, day, and year into mm , dd, yyyy formats and then combines to be YYYYMMDD
 
FOR /F "TOKENS=1* DELIMS= " %%A IN (‘DATE/T’) DO SET CDATE=%%B
FOR /F "TOKENS=1,2 eol=/ DELIMS=/ " %%A IN (‘DATE/T’) DO SET mm=%%B
FOR /F "TOKENS=1,2 DELIMS=/ eol=/" %%A IN (‘echo %CDATE%’) DO SET dd=%%B
FOR /F "TOKENS=2,3 DELIMS=/ " %%A IN (‘echo %CDATE%’) DO SET yyyy=%%B
SET date=%yyyy%-%mm%-%dd%

@REM Query Terminal Session ID so we can gather the source computer

query session %username% > %temp%\tempsession.txt
FOR /F "skip=1 tokens=3 delims= " %%A IN (%temp%\tempsession.txt) Do set Session=%%A
set key=HKEY_CURRENT_USER\Volatile Environment\%Session%
for /f "Tokens=3" %%a IN (‘reg query "%key%" /V "CLIENTNAME"’) do set clientname=%%a
del %temp%\tempsession.txt

echo logon,%username%,%clientname%,%computername%,%date%,%time% >> \\server\share$\logon.log

Here is how I created the GPO to test.

1. Open up GPMC

2. Right click on Group Policy Objects and Name the GPO

3. Right click on new GPO and select Edit

4. Open User Configuration – Policies – Windows Settings – Scripts

5. Right click Logon, select Properties and Add the Logon script.  Do the same for the Logoff.

6. Open Computer Configuration – Policies – Administrative Templates – System – Group Policy – User Group Policy Loopback Processing.

7. Click Enable and select replace.

8. Create an OU and place a test server inside the OU.

9. Link the new GPO to the OU.

10. Logon to the server and validate the the script has placed an entry into the log file.





Exchange 2010 Correlation Engine

8 05 2012

Creating overrides for the Exchange Correlation engine is not easy. Here is a link that shows you how to correctly change the monitors or rules.

http://social.technet.microsoft.com/Forums/en-US/operationsmanagermgmtpacks/thread/28ffced4-7dd9-4731-a8e9-ee0fc2130f47

Often the rules or monitors are using numerical values for severity and priority. Here is an article that shows what the numerical values are.

http://blogs.msdn.com/b/mariussutara/archive/2007/12/17/alert-severity-and-priority-use-with-override.aspx





Get a Computers Uptime using PowerShell

1 02 2012

Here is a PowerShell script that will prompt you for a computer name and it will output the uptime.

###########################################################################
#
# NAME: Get Computer Uptime
#
# AUTHOR:  randolph.brady
#
# COMMENT:
#
# VERSION HISTORY:
# 1.0 1/23/2012 – Initial release
#
###########################################################################

$computer = read-host "Please type in computer name you would like to check uptime on"

$lastboottime = (Get-WmiObject -Class Win32_OperatingSystem -computername $computer).LastBootUpTime

$sysuptime = (Get-Date) – [System.Management.ManagementDateTimeconverter]::ToDateTime($lastboottime)
 
Write-Host "$computer has been up for: " $sysuptime.days "days" $sysuptime.hours "hours" $sysuptime.minutes "minutes" $sysuptime.seconds "seconds"





Reboot Computer using PowerShell

1 02 2012

Here is a script you can use to schedule a server reboot or manually reboot one.  There are two arguments used, –server (server name) and –to (who to send the email to).

###########################################################################
#
# NAME: Reboot Server
#
# AUTHOR:  randolph.brady
#
# COMMENT: You will supply the server and email To: parameters
#(Ex. reboot-server.ps1 -server mpbrandolph01 -to randolph.brady@company.com
#
# VERSION HISTORY:
# 1.0 2/1/2012 – Initial release
#
###########################################################################
param ($server, $to)
 
$resource = $ENV:COMPUTERNAME

if (($server -eq $null) -or ($to -eq $null)) {

Write-Host "`nThere are attributes missing from the script. `n
Please use -server and -to to identify the server to reboot `r
and to who the email should be sent. `n"
Exit
}
 
## Generate an email.  If you don’t have an attachment, remove the attachment parameter in Send-Mailmessage
$body = "This is a scripted reboot of $server from $resource."
$from = "networkservices@company.com"
$subject = "Rebooting $server"
$smtpServer = "smtp.company.corp"

Send-MailMessage -To $to -From $from -Subject $subject -Body $body -SmtpServer $smtpServer

Restart-Computer -ComputerName $server -Force





Create Shares on Remote Servers

12 12 2011

Here is a script that will connect to a list of servers, create a folder structure and then create a share on a folder. 

###########################################################################
#
# NAME: Create Share on Remote Servers
#
# AUTHOR:  Brady Randolph
#
# COMMENT:
#
# VERSION HISTORY:
# 1.0 12/8/2011 – Initial release
#
###########################################################################
##    Gather list of server names
$utlservrs = Get-Content c:\admin\utl_servers.txt

##    Loop through each server
foreach ($s in $utlservrs) {
   
    ##    Create folder structure
    if (Test-Path -Path "\\$s\d$\admin") { "Admin folder exists"
    New-Item -ItemType directory "\\$s\d$\admin\DAGFileShareWitness"
    }
    else {"Admin folder doesn’t exist"
    New-Item -ItemType directory "\\$s\d$\admin\"
    New-Item -ItemType directory "\\$s\d$\admin\DAGFileShareWitness"
    }
##    Create folder share   
"Creating Share"   
$cshare = [WMIClass]"\\$s\root\cimv2:Win32_Share"
$result = $cshare.create("D:\admin\DAGFileShareWitness","DAGFileShareWitness",0,25,"DAG File Share Witness")
"Return Result: $result.ReturnValue"

"Adding Exchange Trusted Subsystem group to local admins"
    $Domain = ‘mydomain.corp’
    $ADGroup = ‘Exchange Trusted Subsystem’
    ([ADSI]"WinNT://$s/Administrators,group").add("WinNT://$Domain/$ADGroup,group")
}





Token Bloating

5 10 2011

Here is an article that explains what token bloating is and how to avoid it within your AD environment.  What this article doesn’t explain is the equation to calculate your token size and that is SIZE = 1200 + 40d + 8s where d = domain local groups and s = global and universal groups.

http://www.itadmintools.com/2011/09/avoiding-token-bloat-in-your-active.html

If your environment is already experiencing this issue, here is an article that explains how to increase your token size within AD.

http://support.microsoft.com/kb/327825





Collect Page File Server Configurations

29 09 2011

A client asked me to write a script to gather the page file configurations for ever server in their domain.  At first thought, I was like this will be a piece of cake.  I can use Win32_PageFile WMI class but the class has been deprecated. At second glance, not that difficult just some understanding of the differences between each OS (2008 R2 and 2000) and which WMI classes to use. 

First let’s start with server 2008.  There is the default configuration to “Automatically manage paging file size for all drives.”  This is not available in server 2003 or 2000 and can be found in Win32_ComputerSystem under AutomaticManagedPagefile.  If this is set to true, paging is automatically managed by the OS and the WMI class Win32_PageFileSetting is never created within the OS. 

image

If it is set to false, you can query Win32_PageFileSetting and gather information from that class which includes initial and max page file sizes.

On server 2003, “Automatically manage page file sizes for all drives” isn’t an option so Win32_PageFileSetting is always available. 

Here are a few links to articles I used:

http://www.planetmps.com/Essentials/Properties/CIMV2/ms_409/Win32/Win32_ComputerSystem.html

http://msdn.microsoft.com/en-us/library/aa394245(v=VS.85).aspx

http://msdn.microsoft.com/en-us/library/aa394246(v=VS.85).aspx

http://msdn.microsoft.com/en-us/library/aa394243(v=VS.85).aspx

The script queries AD and loops through a list of servers and exports data to an Excel document.

##################################################################################
##    This script is used to query every server for their page file configs       
##    1. Connect to the domain using ADSI                                            
##  2. Opens Excel, Add a workbook and deletes default workbooks 2 and 3       
##  3. Builds Array of Values to display in header                                
##  4. Creates Excel Header                                                       
##    5. Loop through each server                                                   
##    6. Collect data on each server                                               
##  7. Exports array to Excel                                                   
##  8. Autofit Excel columns                                                   
##  9. Get Time and Date                                                       
##  10. Save Workbook                                                           
##    Script written by Brady Randolph of RBA Consulting 9/29/2011               
##################################################################################

##  1. Connect to the domain using ADSI
$objDomain = [adsi] (“LDAP://OU=Servers,OU=Company,dc=domain,dc=corp”)
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = $objDomain
$objSearcher.PageSize = 1000
$objSearcher.Filter = ‘(objectClass=Computer)’
$colResults = $objSearcher.FindAll()

##  2. Opens Excel, Add a workbook and deletes default workbooks 2 and 3
    $excel = new-object -comobject excel.application
    $excel.visible = $true
    $workbook = $excel.workbooks.add()
    $workbook.WorkSheets.item(3).delete()
    $workbook.WorkSheets.item(2).delete()
    #Names the worksheet
    $workbook.WorkSheets.item(1).Name = "Servers"
    $sheet = $workbook.WorkSheets.Item("Servers")

    $lineStyle = "microsoft.office.interop.excel.xlLineStyle" -as [type]
    $colorIndex = "microsoft.office.interop.excel.xlColorIndex" -as [type]
    $borderWeight = "microsoft.office.interop.excel.xlBorderWeight" -as [type]
    $chartType = "microsoft.office.interop.excel.xlChartType" -as [type]
   
    ##  3. Builds Array of Values to display in header
    $Borders = @("Server","Pagefile Location","Automanaged","Pagefile Size","RAM Size","PF Initial Size","PF Max Size","System Drive Free Space","Data Drive Free Space")
    $b = 1
   
    ##  4. Creates Excel Header
    Foreach ($item in $Borders) {
        $sheet.cells.item(1,$b).interior.ColorIndex = 1
        $sheet.cells.item(1,$b).font.bold = $true
        $sheet.cells.item(1,$b).font.colorindex = 2
        $sheet.cells.item(1,$b).borders.LineStyle = $lineStyle::xlContinuous
        $sheet.cells.item(1,$b).borders.ColorIndex = $colorIndex::xlColorIndexAutomatic
        #$sheet.cells.item(1,$b).borders.Weight = $borderWeight::xlMedium
        $sheet.cells.item(1,$b) = $item
        $b = $b + 1
    }
    $x = 2
   
##    5. Loop through each server
foreach ($i in $colResults){
    # Set variables to null
    $Server = $null;$PageFileLocation = $null;$SystemManaged = $null;$PageFileSize = $null;$physicalmem = $null;$SysDriveFreeSpace = $null;$DDriveFreeSpace = $null;
    $PFInitial = $null;$PFMax = $null;
    # Set server name to a string
    [string]$server = $i.properties.name
    $OS_Ver = $i.Properties.operatingsystem
    If (($OS_Ver -like "*server*") -and (Test-Connection -ComputerName $server -Count ’2′)){
        $os = get-wmiobject Win32_OperatingSystem -ComputerName $server
        # Verify if server is 2008 R2 because AutomaticManagedPagefile isn’t an property 2000 and 2003
        if ($os.Version -like "6.1*")  {
            $SystemManaged  = Get-WmiObject -ComputerName $server -Class Win32_ComputerSystem | % {$_.AutomaticManagedPagefile}
            if ($SystemManaged -eq "True"){
           
            ##  6. Collect data on each server
                $physicalmem = gwmi -computer $server Win32_ComputerSystem | % {[Math]::round($_.TotalPhysicalMemory/1MB,0)}
                #$SystemManaged  = Get-WmiObject -ComputerName $server -Class Win32_ComputerSystem | % {$_.AutomaticManagedPagefile}
                $PF = gwmi -computer $server Win32_PageFileUsage
                $PageFileLocation = $PF.Name; $PageFileSize = $PF.AllocatedBaseSize
                $LogicalDrives = Get-WmiObject Win32_logicaldisk -ComputerName $server -Filter "DriveType=’3′"
                    Foreach ($drive in $LogicalDrives) {
                        If ($drive.DeviceID -eq ‘c:’){$SysDriveFreeSpace = [Math]::round($drive.FreeSpace / 1GB,0)}
                        elseif ($drive.DeviceID -eq ‘d:’){$DDriveFreeSpace = [Math]::round($drive.FreeSpace / 1GB,0)}
                        elseif ($drive.DeviceID -eq ‘s:’){$SysDriveFreeSpace = [Math]::round($drive.FreeSpace / 1GB,0)}
                        elseif ($drive.DeviceID -eq ‘t:’){$DDriveFreeSpace = [Math]::round($drive.FreeSpace / 1GB,0)}
                    }
                   
                $values = @($Server,$PageFileLocation,$SystemManaged,$PageFileSize,$physicalmem,$PFInitial,$PFMax,$SysDriveFreeSpace,$DDriveFreeSpace)
                            $y = 1
                           
                            ##  7. Exports array to Excel
                            foreach ($val in $values) {
                                #Add Values to row x and column y
                                $sheet.cells.item($x,$y) = $val
                                #increase column by 1
                                $y = $y + 1}
            }
            else{
           
            ##  6. Collect data on each server
                $physicalmem = gwmi -computer $server Win32_ComputerSystem | % {[Math]::round($_.TotalPhysicalMemory/1MB,0)}
                #$SystemManaged  = Get-WmiObject -ComputerName $server -Class Win32_ComputerSystem | % {$_.AutomaticManagedPagefile}
                $PF = gwmi -computer $server Win32_PageFileUsage
                $PageFileLocation = $PF.Name; $PageFileSize = $PF.AllocatedBaseSize
                $LogicalDrives = Get-WmiObject Win32_logicaldisk -ComputerName $server -Filter "DriveType=’3′"
                    Foreach ($drive in $LogicalDrives) {
                        If ($drive.DeviceID -eq ‘c:’){$SysDriveFreeSpace = [Math]::round($drive.FreeSpace / 1GB,0)}
                        elseif ($drive.DeviceID -eq ‘d:’){$DDriveFreeSpace = [Math]::round($drive.FreeSpace / 1GB,0)}
                        elseif ($drive.DeviceID -eq ‘s:’){$SysDriveFreeSpace = [Math]::round($drive.FreeSpace / 1GB,0)}
                        elseif ($drive.DeviceID -eq ‘t:’){$DDriveFreeSpace = [Math]::round($drive.FreeSpace / 1GB,0)}
                    }
                $PageFileSetting = Get-WmiObject Win32_PageFileSetting -ComputerName $server
                $PFInitial = $PageFileSetting.InitialSize; $PFMax = $PageFileSetting.MaximumSize
                $values = @($Server,$PageFileLocation,$SystemManaged,$PageFileSize,$physicalmem,$PFInitial,$PFMax,$SysDriveFreeSpace,$DDriveFreeSpace)
                            $y = 1   
                           
                            ##  7. Exports array to Excel
                            foreach ($val in $values) {
                                #Add Values to row x and column y
                                $sheet.cells.item($x,$y) = $val
                                #increase column by 1
                                $y = $y + 1}
            }
           
            $x = $x + 1
        }
        Else{
       
        ##  6. Collect data on each server
            $physicalmem = gwmi -computer $server Win32_ComputerSystem | % {[Math]::round($_.TotalPhysicalMemory/1MB,0)}
            #$SystemManaged  = Get-WmiObject -ComputerName $server -Class Win32_ComputerSystem | % {$_.AutomaticManagedPagefile}
            $PF = gwmi -computer $server Win32_PageFileUsage
            $PageFileLocation = $PF.Name; $PageFileSize = $PF.AllocatedBaseSize
            $LogicalDrives = Get-WmiObject Win32_logicaldisk -ComputerName $server -Filter "DriveType=’3′"
                Foreach ($drive in $LogicalDrives) {
                    If ($drive.DeviceID -eq ‘c:’){$SysDriveFreeSpace = [Math]::round($drive.FreeSpace / 1GB,0)}
                    elseif ($drive.DeviceID -eq ‘d:’){$DDriveFreeSpace = [Math]::round($drive.FreeSpace / 1GB,0)}
                    elseif ($drive.DeviceID -eq ‘s:’){$SysDriveFreeSpace = [Math]::round($drive.FreeSpace / 1GB,0)}
                    elseif ($drive.DeviceID -eq ‘t:’){$DDriveFreeSpace = [Math]::round($drive.FreeSpace / 1GB,0)}
                }
            $PageFileSetting = Get-WmiObject Win32_PageFileSetting -ComputerName $server
            $PFInitial = $PageFileSetting.InitialSize; $PFMax = $PageFileSetting.MaximumSize
            $values = @($Server,$PageFileLocation,$SystemManaged,$PageFileSize,$physicalmem,$PFInitial,$PFMax,$SysDriveFreeSpace,$DDriveFreeSpace)
                        $y = 1   
                       
                        ##  7. Exports array to Excel
                        foreach ($val in $values) {
                            #Add Values to row x and column y
                            $sheet.cells.item($x,$y) = $val
                            #increase column by 1
                            $y = $y + 1}
            $x = $x + 1
            }
    }
}
## 8.  Autofit Excel columns
$range = $sheet.usedRange
$range.EntireColumn.AutoFit() | out-null

##  9. Get Time and Date
$date = Get-Date -Format "yyyyMMd"
$time = Get-Date -Format "HHms"

##  10. Save Workbook
$strPath = "c:\temp\ServerPageFiles-$date-$time.xls"
$excel.ActiveWorkbook.SaveAs($strPath)
$excel.quit()
spps -n excel





Add Domain Groups to Server Administrators Local Group

27 09 2011

A client of mine wanted to implement AGDLP, Microsoft’s security framework for granting users and groups rights to servers.  This meant I needed to create a domain local group for each server and add that group to the local administrators group.  This script takes a list of servers, creates a domain local group and adds the group to the server local admins.

##################################################################################
##    This script will create a domain local group and add the group to a servers   
##    local administrators group                                                   
##    1. Set Variables                                                            
##  2. Gather list of servers                                                   
##  3. Connect to OU                                                           
##  4. Loop through each server                                                    
##  5. Create group name                                                       
##  6. Create group                                                               
##  7. Create sAMAccountName                                                   
##  8. Set Description                                                           
##  9. Set group security descriptor                                           
##  10. Complete group addition                                                   
##  11. Add group to server local administrators group                           
##    Script written by Brady Randolph of RBA Consulting 9/27/2011               
##################################################################################

## 1. Set your variables
$DLSecDescriptor = ‘-2147483644′
$Domain = ‘Domain.corp’
$objOU = ‘LDAP://OU=Domain Local,OU=Security,OU=Groups,OU=Company,DC=domain,DC=corp’

## 2. Gather list of servers
$List = Get-Content -Path c:\temp\servers.txt

## 3. Connect to OU
$objDomain = New-Object System.DirectoryServices.DirectoryEntry $objOU

if ($List -ne "") {
   
    ## 4. Loop through each server
    foreach ($Comp in $List) {
        ## 5. Create group name
        $DomainLocalGroup = "DL_" + $Comp + "_Local_Admins"
        ## 6. Create group
        $objGroup = $objDomain.Create("group","CN=" + $DomainLocalGroup)
        ## 7. Create sAMAccountName
        $objGroup.Put("sAMAccountName", $DomainLocalGroup)
        ## 8. Set Description
        $objGroup.Put("Description","Nested in Local Administrators on $Comp")
        ## 9. Set group security descriptor
        $objGroup.Put("groupType", $DLSecDescriptor )
        ## 10. Complete group addition
        $objGroup.SetInfo()
       
        ## 11. Add group to server local administrators group
        ([ADSI]"WinNT://$Comp/Administrators,group").add("WinNT://$Domain/$DomainLocalGroup,group")
    }
}





Gather Members of Administrators group on Servers in Active Directory

27 09 2011

##########################################################
##    This script is used to query every servers "local administrators" members
##    1. Set Variables                                                            
##  2. Query all servers within Active Directory                               
##  3. Loop through each server                                                    
##  4. Gather every member of the Administrators group                           
##    5. Add those values to an array                                               
##    6. Export array to a CSV                                                   
##    Script written by Brady Randolph of RBA Consulting 9/27/2011               
##########################################################

#1. Set Variables
$output = ‘c:\temp\ServersLocalAdmins.csv’
## Sets Global Variable for $Now to eliminate repeatable Get-Date queries
$Global:Now = Set-PSBreakpoint -Variable Now -Mode Read -Action {Set-Variable Now (Get-Date) -Option ReadOnly, AllScope -Scope Global -Force}

#2. Connect to the domain using ADSI
$objDomain = [adsi] ("LDAP://OU=Servers,dc=domain,dc=corp")
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = $objDomain
$objSearcher.PageSize = 1000
$objSearcher.Filter = ‘(objectClass=Computer)’
$colResults = $objSearcher.FindAll()
# Creates an empty array
$results = @()

#3. Loop through each server
foreach ($Computer in $colResults) {
    [string]$CompName = $Computer.Properties.name
    #$CompName = $Computer
    $OS_Ver = $Computer.Properties.operatingsystem
    #$OS_Ver = Get-WmiObject -ComputerName $CompName -Class Win32_OperatingSystem | Select-Object {$_.caption}
    #Setting Members to null so values aren’t carried over to next computer
    $members = $null
    If ($OS_Ver -like "*server*"){
        If (Test-Connection -ComputerName $CompName -Count ’2′){
        Out-Host -InputObject "$Now $CompName is Online"
         $group =[ADSI]"WinNT://$CompName/Administrators"
        #4. Gather every member of the Administrators group
        $members = $group.Members() | foreach {$_.GetType().InvokeMember("Name", ‘GetProperty’, $null, $_, $null) }
        #$localmembers | foreach {$_.GetType().InvokeMember("AdsPath","GetProperty",$null,$_,$null)}
        #5. Add those values to an array
        $results += New-Object PsObject -Property @{
        Server = $CompName
        Members = $members -join ";"}
       
          }
   
      Else { Write-Host "$Now $CompName is Offline"}
    }
}
#6. Export array to a CSV
$results | Export-Csv $Output -NoTypeInformation





Displaying Balloon Tip using PoSH

27 09 2011

Let’s assume your script wants to share status information via a balloon message in the system tray area. Here is a sample:

[system.Reflection.Assembly]::LoadWithPartialName(‘System.Windows.Forms’) | Out-Null

$balloon = New-Object System.Windows.Forms.NotifyIcon

$path = Get-Process -id $pid | Select-Object -ExpandProperty Path

$icon = [System.Drawing.Icon]::ExtractAssociatedIcon($path)

$balloon.Icon = $icon

$balloon.BalloonTipIcon = ‘Info’

$balloon.BalloonTipText = ‘Completed Operation’

$balloon.BalloonTipTitle = ‘Done’

$balloon.Visible = $true

$balloon.ShowBalloonTip(10000)

 

Note that the code uses the icon of your PowerShell application inside the tray area so the user can associate the message with the application that produced it.

I received this code from PowerShell.com’s PowerTip of the Day.








Follow

Get every new post delivered to your Inbox.