June 18 2015

Why we need to keep Domain Controllers physically secure



----------------------------------------------------------------------------
I use a maximum of one Google Ad per post to help offset some of my blog hosting costs.

----------------------------------------------------------------------------

This purpose of this post is to highlight another reason we need to keep Domain Controllers physically secure – in fact the principle here also applies to standard Windows Servers too.

My home test lab had been powered down for a few months and I’d forgotten my Domain Administrator password. I knew there was a method to log onto a Windows Server without a username and password back in Windows Server 2003 and I thought that surely this still wouldn’t work with Windows Server 2012 R2 – however to my horror it still did. Here is how I reset my Domain Administrator account password – scary stuff!

Forgotten password
Forgotten password
Forgotten password
Forgotten password

So I’d forgotten my Domain Administrator password. Time to attach the Windows Server 2012 R2 ISO to the VM.

Attach ISO
Attach ISO

Adjust the boot order to force booting from ISO first.

Boot to DVD/ISO

Restart the VM and boot to the DVD/ISO. Click Next on the first setup screen. On the following screen make sure you select “Repair your computer”.

Next
Next
Repair your computer
Repair your computer

Then click on “Troubleshoot” followed by “Command Prompt”

Troubleshoot
Troubleshoot
Command Prompt
Command Prompt

You will now be presented with a Command Prompt.  Change your directory to c:\Windows\System32.  Then rename the Utilman.exe executable by running the command “ren Utilman.exe Utilman.exe.old”.  Then make a copy of cmd.exe named Utilman.exe using the command “copy cmd.exe Utilman.exe”.  See below screenshot.

Replace Utilman
Replace Utilman

Close the command prompt and restart the machine, booting back into the regular Windows logon screen.  Once the logon screen is presented, press the “Windows Key” and “U”.  Much to your horror you will see a Command Prompt appear. If you check Task Manager, you will see that the Command Prompt (executable called Utilman.exe) is running in the SYSTEM context.  Given that this is a Domain Controller, effectively this mean the commands run within the Command Prompt are executed with the Domain Admin permission level.

SYSTEM context
SYSTEM context

To reset the Domain Administrator account password, we simply need to run the “net user Administrator password” command.

Reset password

You can now close the Command Prompt and log onto the domain with the Administrator account and the newly set password.

I have also seen this work with the Sticky Keys executable (sethc.exe) being replaced instead of Utilman.exe.

 

Once again this highlights why we need to keep our Domain Controllers physically secure – from this demo you can see that anyone with physical access to the server can have control over your entire Active Directory domain in a very short amount of time!

 



----------------------------------------------------------------------------
I use a maximum of one Google Ad per post to help offset some of my blog hosting costs.

----------------------------------------------------------------------------

October 31 2014

Moving my WordPress blog to Azure

Here’s a little about my experience moving the hosting of this WordPress blog to the Azure platform.

I had been using Webcity to host this blog for many years. I would constantly receive warnings about CPU spikes from them because their solution doesn’t scale. This led to my account being suspended a number of times this year and in one week last month there were 2 x 8 hour+ unexplained  & un-communicated outages for all hosted websites – this pushed me over the edge to look at other solutions. I liked the idea of more stable infrastructure and the flexibility to scale up and down.

Webcity charged me $150AU per year. Using CPanel, I worked out that my total HTTP traffic per month averaged over the last 6 months is 6GB per month. Based on the Azure pricing calculator (http://azure.microsoft.com/en-us/pricing/calculator/), this means I should actually be saving around $30 per year by using Azure.

calc

To get started, I logged onto https://manage.windowsazure.com and associated my credit card with my existing Windows Live ID (or whatever it is called now). From there, I simply opened the Azure management website, went to Web Sites, Create a Web Site and then From Gallery:

azure1

Selected WordPress, then filled in the site details:

azure2

On the next page, accept the new Database name or create your own.

After a few minutes, the new website will appear and go into ‘Running’ status. Select the instance and click ‘Browse’:
azure3
Fill in your details, these are only temporary as you can change them later. Hit ‘Install WordPress’. After a few minutes there will be a success page.
azure4
A basic WordPress site is now up and running, you can visit the URL that you chose at the start – in my case it was http://danovich.azurewebsites.net/ .
The default option is to set up the web hosting plan as ‘Free’, however this doesn’t allow for a custom domain name (danovich.com.au).From the help page: Each plan has a mode associated with it. Different modes expose different sets of features and capabilities. Plans in the Free and Shared modes run on a shared infrastructure with sites managed by other customers. These sites will have strict quotas for resource utilization. Plans in the Basic and Standard modes run on resources that are dedicated to your sites and have fewer restrictions. Also see http://azure.microsoft.com/en-us/pricing/details/websites/To configure this, head back to the Azure management portal, select your website and click on ‘Scale’.  In my case I selected Shared, this will be enough for me for now and the beauty of Azure is that I can upgrade to a different plan easily later on if needed.

azure5

I originally planned to use a migration tool to move across the site configuration and content however I ran into multiple errors no matter which migration tool I tried:

  • All-in-One WP Migration
  • WP Clone by WP Academy
  • WordPress Move
  • WP Migrate DB
  • UpdraftPlus
  • Duplicator

I put this down to the fact that I had a very old and unsupported WordPress theme running plus 6+ years of WordPress customizations. I decided not to use the migration plugin tools and went for using the freshly installed WordPress instance on Azure, picked a new theme, added a handful of useful plugins and then used the native export and import functionality of WordPress to get the old posts across. I then used FTP to copy to uploads directory across.

azure6

I remembered that my DNS was hosted with my old web hosting provider, so I upgraded my domain registration provider account to also host by DNS. I entered my handful of A and CNAME records and waited til the next day for replication around the Internet. At the same time, I added an additional A record for migrate.danovich.com.au that pointed to the IP address provided by Azure (screenshot below) and also a CNAME for awverify.migrate.danovich.com.au  to point to awverify.migrate.danovich.azurewebsites.net for the purposes of testing before cutting over the remaining DNS records.

After waiting for replication, I went into the Azure management portal –> configuration –> domain names  –> manage domains, where I added the new line for migrate.danovich.com.au.  I could then use my browser to see that migrate.danovich.com.au was now showing my new website hosted on Azure.  The next step was to update my remaining A & CNAME DNS records to point to the IP address or the awverify CNAME that Azure needs for verification.

DNS records
DNS records
Manage custom domains
Manage custom domains

Once this was done, I could access the website using blog.danovich.com.au or any of the other DNS entries I had added.

Whilst it was very easy to set up a WordPress instance on Azure and relatively easy to import my old content, I’ve had a few issues using Azure – specifically around billing and availability –  to the point where I don’t see me continuing to use Azure in the future. I’ll save that for another post…… but overall it was a very easy process to get WordPress up and running on Azure.

May 21 2013

Powershell Domain Controller audit script

This Powershell script will audit your Active Directory Domain Controllers for a given domain and return a whole bunch of useful information via CSV or Excel:

 

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

# Adjustable variables (5)

# Manual safe guard to ensure scope is limited
# Set the name of the Active Directory domain to query, eg $DomainDNS = "danovich.com.au"
# $DomainDNS value is ignored if the $SpecificDC value is set to anything after from null

$DomainDNS = "danovich.com.au"

# If this value is set, only a specific Domain Controller is queried
# For example, to only query TESTDC01, set $SpecificDC = "TESTDC01"
# Otherwise set $SpecificDC = $null and all Domain Controllers will be discovered and queried

$SpecificDC = $null

# Set the timeout in milliseconds for ping command, eg $Timeout = 500
# Some enviornments may need a larger value

$Timeout = 5000

# Set the type of output required, either:
#  "Excel" - Nicely formatted Excel spreadsheet formatting - requires Excel installed on host
#  "CSV" - Basic text output to CSV file for further manipulation

$OutputFormat = "CSV"

# If using CSV, specify the name and location of the CSV file to be created, eg $FileLocation = "c:tempExportDCs.csv"

$FileLocation = "c:tempExportDCs.csv"

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

# AUTHOR: blog.danovich.com.au
# DATE:  16/05/2013
# NAME:  Domain_Controllers_Audit.ps1
# VERSION: 1.7
# PURPOSE: Audit Active Directory Domain Controllers
# COMMENT: 1.0 Initial release after testing
#   1.1 Adjusted $DomainControllers = Get-ADDomainController -Domain $DomainDNS query
#   1.2 Added support for Windows 2003 Server queries - previously was only 2008 OS and above
#       Ability to query only one particular Domain Controller
#   1.3 Fixed incorrect CPU core counting
#   1.4 Added WMI connectivity check
#   1.5 Added checks for disk space, SCCM & SCOM agents
#   1.6 Added progress bar
#   1.7 Fixed incorrect virtual machine query

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

# REQUIREMENTS:

# To run the PowerShell script, the correct Execution Policy level must be set (Set-ExecutionPolicy)
# The user account running this script must have permission to:
#               - Remotely query WMI on Domain Controllers
#               - Query Active Directory attributes of Domain Contollers
# Network connectivity from the host where script is running to all Domain Controllers in the domain including:
#               - ICMP (for ping)
#               - TCP & UDP ports for remote WMI queries
#               - Consider both hardware and software firewalls
# Micorosft Office Excel must be installed on the host running this script if $OutputFormat = "Excel"
# Run from within the Active Directory Module for PowerShell (or import the Active Directory PS module into the PS session)

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

# Check if $SpecificDC value is not null

if ($SpecificDC)
{
$DomainControllers = Get-ADDomainController $SpecificDC
}

else

{

# Domain Controller discovery

clear
write-host "" `r
Write-host "Discovering all DCs in the domain $DomainDNS ....." `r
Write-host "`n"
$DomainControllers = Get-ADDomainController -Filter * -Server $DomainDNS

}
# Output list of Domain Controllers to screen
ForEach ($DC in $DomainControllers)
{
Write-Host $DC.Name
}
##########################################################
# Start of Excel section
##########################################################

if ($OutputFormat -eq "Excel")
{

# Set up Excel spreadsheet

$erroractionpreference = "SilentlyContinue"
$a = New-Object -comobject Excel.Application
$a.visible = $True
$b = $a.Workbooks.Add()
$c = $b.Worksheets.Item(1)
$c.Cells.Item(1,1) = "Name"
$c.Cells.Item(1,2) = "Description"
$c.Cells.Item(1,3) = "Ping Status"
$c.Cells.Item(1,4) = "FQDN"
$c.Cells.Item(1,5) = "IP Address"
$c.Cells.Item(1,6) = "Operating System"
$c.Cells.Item(1,7) = "Service Pack"
$c.Cells.Item(1,8) = "Domain"
$c.Cells.Item(1,9) = "GC"
$c.Cells.Item(1,10) = "FSMO Roles"
$c.Cells.Item(1,11) = "AD Site"
$c.Cells.Item(1,12) = "Read Only"
$c.Cells.Item(1,13) = "LDAP Port"
$c.Cells.Item(1,14) = "SSL Port"
$c.Cells.Item(1,15) = "Roles Installed"
$c.Cells.Item(1,16) = "Last Boot Time"
$c.Cells.Item(1,17) = "Virtual"
$c.Cells.Item(1,18) = "DNS Servers"
$c.Cells.Item(1,19) = "RAM (MB)"
$c.Cells.Item(1,20) = "CPU Speed (MHz)"
$c.Cells.Item(1,21) = "CPU Cores"
$c.Cells.Item(1,22) = "Logical CPUs"
$c.Cells.Item(1,23) = "Timezone"
$c.Cells.Item(1,24) = "Free space (C: GB)"
$c.Cells.Item(1,25) = "SCCM Client"
$c.Cells.Item(1,26) = "SCOM Client"
$c.Cells.Item(1,27) = "Query Time"
$d = $c.UsedRange
$d.Interior.ColorIndex = 19
$d.Font.ColorIndex = 11
$d.Font.Bold = $True
$d.EntireColumn.AutoFit($True)
$intRow = 2
# Start querying each Domain Controller

ForEach ($DC in $DomainControllers)
{
# Output progress bar to the screen

$i++
$numberofDCs = $DomainControllers.count
$ProgressName = $DC.Name
Write-Progress -Activity "Collecting Domain Controller information" -status "Contacting $ProgressName [$i out of $numberofDCs].  Overall percentage complete:" -percentComplete ($i / $DomainControllers.count*100)
# Write Domain Controller name in capitals

$c.Cells.Item($intRow, 1) = $DC.Name.ToUpper()
# Test connectivity from host to each Domain Controller

$ping = new-object System.Net.NetworkInformation.Ping
$Reply = $ping.send($DC.Name,$Timeout)
if ($Reply.status -eq "Success")
{
$DCPing = "Resolved & active"
$Online = $true
}
elseif ($Reply.status -eq "TimedOut")
{
$DCPing = "Resolved host but timed out"
$Online = $false
}
else
{
$DCPing = "Unable to resolve"
$Online = $false
}
$Reply = ""
# Write ping status

$c.Cells.Item($intRow, 3) = $DCPing
# Check WMI connectivity

$wmi = $null
$wmi = Get-WmiObject -class Win32_ComputerSystem -ComputerName $DC.Name -ErrorAction SilentlyContinue

if ($wmi)
{
# Able to connect to WMI
$ConnectViaWmi = $True
}
else
{
# Unable to connect to WMI
$ConnectViaWmi = $False
}
# Query and write computer description retrieved from AD

$DCDesc = (Get-ADComputer -Properties * -Filter {name -like $DC.Name}).Description
$c.Cells.Item($intRow, 2) = $DCDesc
# Query and write computer FQDN retrieved from AD

$DCFQDN = (Get-ADComputer -Properties * -Filter {name -like $DC.Name}).DNSHostName
$c.Cells.Item($intRow, 4) = $DCFQDN
# Query and write computer IPv4 address retrieved from AD

$DCIPv4 = (Get-ADComputer -Properties * -Filter {name -like $DC.Name}).IPv4Address
$c.Cells.Item($intRow, 5) = $DCIPv4
# Query and write computer Operating System retrieved from AD

$DCOS = (Get-ADComputer -Properties * -Filter {name -like $DC.Name}).OperatingSystem
$c.Cells.Item($intRow, 6) = $DCOS
# Query and write computer Operating System Service Pack retrieved from AD

$DCOSSP = (Get-ADComputer -Properties * -Filter {name -like $DC.Name}).OperatingSystemServicePack
$c.Cells.Item($intRow, 7) = $DCOSSP
# Query and write computer domain retrieved from AD

$DCDomain = (Get-ADDomainController -Filter {name -like $DC.Name}).Domain
$c.Cells.Item($intRow, 8) = $DCDomain
# Query and write computer global catalog boolean retrieved from AD

$DCGC = (Get-ADDomainController -Filter {name -like $DC.Name}).IsGlobalCatalog
$c.Cells.Item($intRow, 9) = $DCGC
# Query and write computer FSMO roles retrieved from AD

$DCFSMOOutput = ((Get-ADDomainController -Filter {name -like $DC.Name}).OperationMasterRoles | Out-String)
$DCFSMO = ($DCFSMOOutput).Replace("`n",'  ')
$c.Cells.Item($intRow, 10) = $DCFSMO
# Query and write computer AD site info retrieved from AD

$DCSite = (Get-ADDomainController -Filter {name -like $DC.Name}).Site
$c.Cells.Item($intRow, 11) = $DCSite
# Query and write computer read-only domain controller info retrieved from AD

$DCRO = (Get-ADDomainController -Filter {name -like $DC.Name}).IsReadOnly
$c.Cells.Item($intRow, 12) = $DCRO
# Query and write computer LDAP port retrieved from AD

$DCLDAP = (Get-ADDomainController -Filter {name -like $DC.Name}).LdapPort
$c.Cells.Item($intRow, 13) = $DCLDAP
# Query and write computer SSL port retrieved from AD

$DCSLDAP = (Get-ADDomainController -Filter {name -like $DC.Name}).SSLPort
$c.Cells.Item($intRow, 14) = $DCSLDAP
# Query the Server Roles that are installed on the Domain Controller (eg DNS, DHCP, ADDS)
# Assuming role ID is less than 30 - http://msdn.microsoft.com/en-gb/library/windows/desktop/cc280268(v=vs.85).aspx

if ($Online -eq $true -and $DCOS -notlike "*2003*" -and $ConnectViaWmi -eq $true)
{
$DCRole = (gwmi win32_ServerFeature -filter "ID<30" -computername $DC.Name | Select-Object "Name")
$k = @()
foreach ($j in $DCRole)
{$k += $j.Name
$c.Cells.Item($intRow, 15) = ($k -Join ', ')}
}
elseif ($Online -eq $false)
{
$c.Cells.Item($intRow, 15) = "Cannot query - Ping timeout"
}
elseif ($ConnectViaWmi -eq $false -and $DCOS -notlike "*2003*")
{
$c.Cells.Item($intRow, 15) = "Cannot connect to WMI"
}
elseif ($DCOS -like "*2003*")
{
$c.Cells.Item($intRow, 15) = "N/A - Windows 2003 Server OS"
}
# Query last boot time

if ($Online -eq $true -and $ConnectViaWmi -eq $true)
{
$date = new-object -com WbemScripting.SWbemDateTime
$z = get-wmiobject Win32_OperatingSystem -computername $DC.Name
foreach ($k in $z)
{$date.value = $k.lastBootupTime
If ($k.Version -eq "*" )
{$c.Cells.Item($intRow, 16) = $Date.GetVarDate($True)}
Else
{$c.Cells.Item($intRow, 16) = $Date.GetVarDate($False)}
}
}
elseif ($Online -eq $false)
{
$c.Cells.Item($intRow, 16) = "Cannot query - Ping timeout"
}
elseif ($ConnectViaWmi -eq $false)
{
$c.Cells.Item($intRow, 16) = "Cannot connect to WMI"
}
# Query if virtual machine / virtual hardware

$DCVM = $null
if ($Online -eq $true -and $ConnectViaWmi -eq $true)
{
$bios = gwmi Win32_BIOS -computername $DC.Name | Select-Object "version","serialnumber"
$compsys = gwmi Win32_ComputerSystem -computername $DC.Name | Select-Object "model","manufacturer"

if($bios.Version -match "VRTUAL") {$DCVM = "Virtual - Hyper-V"}
elseif($bios.Version -match "A M I") {$DCVM = "Virtual -  Virtual PC"}
elseif($bios.Version -like "*Xen*") {$DCVM = "Virtual - Xen"}
elseif($bios.SerialNumber -like "*VMware*") {$DCVM = "Virtual - VMWare"}
elseif($compsys.manufacturer -like "*Microsoft*") {$DCVM = "Virtual - Hyper-V"}
elseif($compsys.manufacturer -like "*VMWare*") {$DCVM = "Virtual - VMWare"}
elseif($compsys.model -like "*Virtual*") {$DCVM = "Virtual"}
else {$DCVM = "Physical"}
}
elseif ($Online -eq $false)
{
$DCVM = "Cannot query - Ping timeout"
}
elseif ($ConnectViaWmi -eq $false)
{
$DCVM = "Cannot connect to WMI"
}
# Query machine network cards to see which DNS Servers are used for queries

if ($Online -eq $true -and $ConnectViaWmi -eq $true)
{
$Adapters = Get-Wmiobject Win32_NetworkAdapterConfiguration -Computername $DC.Name | Where-Object{$_.IPEnabled -eq $True}
ForEach($Adapter In $Adapters)
{
[String]$DNSServers = ""
$Adapters2 = Get-Wmiobject Win32_NetworkAdapter -Computername $DC.Name | Where-Object{$_.Caption -eq $Adapter.Caption}
[String]$NetID = $Adapters2.NetConnectionID
If($Adapter.DNSServerSearchOrder -ne $Null)
{ForEach($Address In $Adapter.DNSServerSearchOrder)
{$DNSServers += $Address + "  "}
}
}
}
elseif ($Online -eq $false)
{
$DNSServers = "Cannot query - Ping timeout"
}
elseif ($ConnectViaWmi -eq $false)
{
$DNSServers = "Cannot connect to WMI"
}
# Output time of query

$datetime = get-date -uformat "%d/%m/%Y %H:%M:%S"
$UTC = get-date -uformat "%Z"
$querytime = $datetime + " UTC " + $UTC
# Check amount of installed RAM

if ($Online -eq $true -and $ConnectViaWmi -eq $true)
{
$colItems = get-wmiobject -class "Win32_ComputerSystem" -namespace "rootCIMV2" -computername $DC.Name
foreach ($objItem in $colItems)
{$DCRAM = [math]::round($objItem.TotalPhysicalMemory/1024/1024, 0)}
}
elseif ($Online -eq $false)
{
$DCRAM = "Cannot query - Ping timeout"
}
elseif ($ConnectViaWmi -eq $false)
{
$DCRAM = "Cannot connect to WMI"
}
# Query CPU information

if ($Online -eq $true -and $DCOS -notlike "*2003*" -and $ConnectViaWmi -eq $true)
{
$CPUproperty = "maxclockspeed", "numberOfCores", "NumberOfLogicalProcessors"
$DCCPUSpeed = Get-WmiObject -class "win32_processor" -Property $CPUproperty -computername $DC.Name -filter "deviceid='CPU0'" | Select-Object -expand "maxclockspeed"
$Win32_cpu = Get-WmiObject -class win32_processor -computername $DC.Name
$DCCPULogical = ($Win32_cpu | measure-object).count
$DCCPUCores = ($Win32_cpu | measure-object NumberOfCores -sum).sum
}

elseif ($Online -eq $true -and $DCOS -like "*2003*" -and $ConnectViaWmi -eq $true)
{
$CPUproperty = "maxclockspeed"
$DCCPUSpeed = Get-WmiObject -class "win32_processor" -Property $CPUproperty -computername $DC.Name -filter "deviceid='CPU0'" | Select-Object -expand "maxclockspeed"
$physCount = new-object hashtable
$Win32_cpu = Get-WmiObject -class win32_processor -computername $DC.Name
$Win32_cpu |%{$physCount[$_.SocketDesignation] = 1}
$DCCPULogical = $physCount.count
$DCCPUCores = ($Win32_cpu | measure-object).count
}

elseif ($Online -eq $false)
{
$DCCPUSpeed = "Cannot query - Ping timeout"
$DCCPUCores = "Cannot query - Ping timeout"
$DCCPULogical = "Cannot query - Ping timeout"
}

elseif ($ConnectViaWmi -eq $false)
{
$DCCPUSpeed = "Cannot connect to WMI"
$DCCPUCores = "Cannot connect to WMI"
$DCCPULogical = "Cannot connect to WMI"
}
# Query timezone information
if ($Online -eq $true -and $ConnectViaWmi -eq $true)
{
$DCTZ = Get-WmiObject -class "Win32_TimeZone" -computername $DC.Name | Select-Object -expand "Caption"
}
elseif ($Online -eq $false)
{
$DCTZ = "Cannot query - Ping timeout"
}
elseif ($ConnectViaWmi -eq $false)
{
$DCTZ = "Cannot connect to WMI"
}
# Query free disk space on C drive

if ($Online -eq $true -and $ConnectViaWmi -eq $true)
{
$Cdisk = Get-WmiObject Win32_LogicalDisk -ComputerName $DC.Name -Filter "DeviceID='C:'" | Select-Object FreeSpace
$Cdisk.FreeSpace = $([Math]::Round($Cdisk.FreeSpace/1073741824,1))
$DCDiskFree = $Cdisk.FreeSpace
}
elseif ($Online -eq $false)
{
$DCDiskFree = "Cannot query - Ping timeout"
}
elseif ($ConnectViaWmi -eq $false)
{
$DCDiskFree = "Cannot connect to WMI"
}

# Check if SCCM client is installed

if ($Online -eq $true -and $ConnectViaWmi -eq $true)
{
$SCCMCheck = get-wmiobject -namespace rootcimv2 -computername $DC.Name -class win32_process -filter 'Name="ccmexec.exe"'

if (-not $SCCMCheck)
{
$DCSCCMClient = "No"
}
else
{
$siteCode = (Get-WmiObject -computername $DC.Name -namespace rootccmpolicymachine -Class CCM_SystemHealthClientConfig).SiteCode
$DCSCCMClient = "Yes - " +$siteCode
}
}
elseif ($Online -eq $false)
{
$DCSCCMClient = "Cannot query - Ping timeout"
}
elseif ($ConnectViaWmi -eq $false)
{
$DCSCCMClient = "Cannot connect to WMI"
}

# Check if SCOM client is installed

if ($Online -eq $true -and $ConnectViaWmi -eq $true)
{
$SCOMCheck = get-wmiobject -namespace rootcimv2 -computername $DC.Name -class win32_process -filter 'Name="HealthService.exe"'

if (-not $SCOMCheck)
{
$DCSCOMClient = "No"
}
else
{

$Path = "hklm:SOFTWAREMICROSOFTMICROSOFT OPERATIONS MANAGER3.0AGENT MANAGEMENT GROUPS"
$baseKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey("LocalMachine", $DC.Name)
$s = ""

## Open the key
$key = $baseKey.OpenSubKey("SOFTWAREMICROSOFTMICROSOFT OPERATIONS MANAGER3.0AGENT MANAGEMENT GROUPS")

## Retrieve all of its children
foreach($subkeyName in $key.GetSubKeyNames())
{
## Open the subkey
$subkey = $key.OpenSubKey($subkeyName)
$returnObject = [PsObject] $subKey
$returnObject | Add-Member NoteProperty PsChildName $subkeyName | Select PSChildName

## Output the key
$s += $returnObject.PsChildName + " "

## Close the child key
$subkey.Close()
}
## Close the key and base keys
$key.Close()
$baseKey.Close()

$DCSCOMClient = "Yes - " +$s
}
}
elseif ($Online -eq $false)
{
$DCSCOMClient = "Cannot query - Ping timeout"
}
elseif ($ConnectViaWmi -eq $false)
{
$DCSCOMClient = "Cannot connect to WMI"
}
# Write out Excel rows for direct machine queries

$c.Cells.Item($intRow, 17) = $DCVM
$c.Cells.Item($intRow, 18) = $DNSServers
$c.Cells.Item($intRow, 19) = $DCRAM
$c.Cells.Item($intRow, 20) = $DCCPUSpeed
$c.Cells.Item($intRow, 21) = $DCCPUCores
$c.Cells.Item($intRow, 22) = $DCCPULogical
$c.Cells.Item($intRow, 23) = $DCTZ
$c.Cells.Item($intRow, 24) = $DCDiskFree
$c.Cells.Item($intRow, 25) = $DCSCCMClient
$c.Cells.Item($intRow, 26) = $DCSCOMClient
$c.Cells.Item($intRow, 27) = $querytime
# Next Excel row

$intRow = $intRow + 1

[array] $DomainDCs += $DC.HostName
$Online = $false

# End of foreach DC

}
# Configure Excel Autofit for rows and columns

$d.EntireColumn.AutoFit()|out-null
$d.EntireRow.AutoFit()|out-null
# Configure Excel Filters - uncomment if required

#$d.EntireColumn.AutoFilter()

Write-host "`n"
Write-Host "Excel file creation complete...."

}

##########################################################
# End of Excel section
##########################################################
##########################################################
# Start of CSV section
##########################################################

if ($OutputFormat -eq "CSV")
{
# Create empty array
$report = @()

$erroractionpreference = "SilentlyContinue"

# Start querying each Domain Controller

ForEach ($DC in $DomainControllers)
{
# Output progress bar to the screen

$i++
$numberofDCs = $DomainControllers.count
$ProgressName = $DC.Name
Write-Progress -Activity "Collecting Domain Controller information" -status "Contacting $ProgressName [$i out of $numberofDCs].  Overall percentage complete:" -percentComplete ($i / $DomainControllers.count*100)
# Test connectivity from host to each Domain Controller

$ping = new-object System.Net.NetworkInformation.Ping
$Reply = $ping.send($DC.Name,$Timeout)
if ($Reply.status -eq "Success")
{
$DCPing = "Resolved & active"
$Online = $true
}
elseif ($Reply.status -eq "TimedOut")
{
$DCPing = "Resolved host but timed out"
$Online = $false
}
else
{
$DCPing = "Unable to resolve"
$Online = $false
}
$Reply = ""
# Check WMI connectivity

$wmi = $null
$wmi = Get-WmiObject -class Win32_ComputerSystem -ComputerName $DC.Name -ErrorAction SilentlyContinue

if ($wmi)
{
# Able to connect to WMI
$ConnectViaWmi = $True
}
else
{
# Unable to connect to WMI
$ConnectViaWmi = $False
}
# Query computer description retrieved from AD

$DCDesc = (Get-ADComputer -Properties * -Filter {name -like $DC.Name}).Description
# Query computer FQDN retrieved from AD

$DCFQDN = (Get-ADComputer -Properties * -Filter {name -like $DC.Name}).DNSHostName
# Query IPv4 address retrieved from AD

$DCIPv4 = (Get-ADComputer -Properties * -Filter {name -like $DC.Name}).IPv4Address
# Query Operating System retrieved from AD

$DCOS = (Get-ADComputer -Properties * -Filter {name -like $DC.Name}).OperatingSystem
# Query Operating System Service Pack retrieved from AD

$DCOSSP = (Get-ADComputer -Properties * -Filter {name -like $DC.Name}).OperatingSystemServicePack
# Query computer domain retrieved from AD

$DCDomain = (Get-ADDomainController -Filter {name -like $DC.Name}).Domain
# Query computer global catalog boolean retrieved from AD

$DCGC = (Get-ADDomainController -Filter {name -like $DC.Name}).IsGlobalCatalog
# Query computer FSMO roles retrieved from AD

$DCFSMOOutput = ((Get-ADDomainController -Filter {name -like $DC.Name}).OperationMasterRoles | Out-String)
$DCFSMO = ($DCFSMOOutput).Replace("`n",'  ')
# Query computer AD site info retrieved from AD

$DCSite = (Get-ADDomainController -Filter {name -like $DC.Name}).Site
# Query read-only domain controller info retrieved from AD

$DCRO = (Get-ADDomainController -Filter {name -like $DC.Name}).IsReadOnly
# Query computer LDAP port retrieved from AD

$DCLDAP = (Get-ADDomainController -Filter {name -like $DC.Name}).LdapPort
# Query computer SSL port retrieved from AD

$DCSLDAP = (Get-ADDomainController -Filter {name -like $DC.Name}).SSLPort
# Query the Server Roles that are installed on the Domain Controller (eg DNS, DHCP, ADDS)
# Assuming role ID is less than 30 - http://msdn.microsoft.com/en-gb/library/windows/desktop/cc280268(v=vs.85).aspx

if ($Online -eq $true -and $DCOS -notlike "*2003*" -and $ConnectViaWmi -eq $true)
{
$DCRole = (gwmi win32_ServerFeature -filter "ID<30" -computername $DC.Name | Select-Object "Name")
$k = @()
foreach ($j in $DCRole)
{$k += $j.Name
$DCRoleOutput = ($k -Join ', ')
}
}
elseif ($Online -eq $false)
{
$DCRoleOutput = "Cannot query - Ping timeout"
}

elseif ($DCOS -like "*2003*")
{
$DCRoleOutput = "N/A - Windows 2003 Server OS"
}

elseif ($ConnectViaWmi -eq $false)
{
$DCRoleOutput = "Cannot connect to WMI"
}

# Query last boot time

if ($Online -eq $true -and $ConnectViaWmi -eq $true)
{
$date = new-object -com WbemScripting.SWbemDateTime
$z = get-wmiobject Win32_OperatingSystem -computername $DC.Name
foreach ($k in $z)
{
$date.value = $k.lastBootupTime
If ($k.Version -eq "*" )
{
$LastBoot = $Date.GetVarDate($True)
}
Else
{
$LastBoot = $Date.GetVarDate($False)
}
}
}
elseif ($Online -eq $false)
{
$LastBoot = "Cannot query - Ping timeout"
}
elseif ($ConnectViaWmi -eq $false)
{
$LastBoot = "Cannot connect to WMI"
}
# Query if virtual machine / virtual hardware

$DCVM = $null
if ($Online -eq $true -and $ConnectViaWmi -eq $true)
{
$bios = gwmi Win32_BIOS -computername $DC.Name | Select-Object "version","serialnumber"
$compsys = gwmi Win32_ComputerSystem -computername $DC.Name | Select-Object "model","manufacturer"

if($bios.Version -match "VRTUAL") {$DCVM = "Virtual - Hyper-V"}
elseif($bios.Version -match "A M I") {$DCVM = "Virtual -  Virtual PC"}
elseif($bios.Version -like "*Xen*") {$DCVM = "Virtual - Xen"}
elseif($bios.SerialNumber -like "*VMware*") {$DCVM = "Virtual - VMWare"}
elseif($compsys.manufacturer -like "*Microsoft*") {$DCVM = "Virtual - Hyper-V"}
elseif($compsys.manufacturer -like "*VMWare*") {$DCVM = "Virtual - VMWare"}
elseif($compsys.model -like "*Virtual*") {$DCVM = "Virtual"}
else {$DCVM = "Physical"}
}
elseif ($Online -eq $false)
{
$DCVM = "Cannot query - Ping timeout"
}
elseif ($ConnectViaWmi -eq $false)
{
$DCVM = "Cannot connect to WMI"
}
# Query machine network cards to see which DNS Servers are used for queries

if ($Online -eq $true -and $ConnectViaWmi -eq $true)
{
$Adapters = Get-Wmiobject Win32_NetworkAdapterConfiguration -Computername $DC.Name | Where-Object{$_.IPEnabled -eq $True}
ForEach($Adapter In $Adapters)
{
[String]$DNSServers = ""
$Adapters2 = Get-Wmiobject Win32_NetworkAdapter -Computername $DC.Name | Where-Object{$_.Caption -eq $Adapter.Caption}
[String]$NetID = $Adapters2.NetConnectionID
If($Adapter.DNSServerSearchOrder -ne $Null)
{ForEach($Address In $Adapter.DNSServerSearchOrder)
{$DNSServers += $Address + "  "}
}
}
}
elseif ($Online -eq $false)
{
$DNSServers = "Cannot query - Ping timeout"
}
elseif ($ConnectViaWmi -eq $false)
{
$DNSServers = "Cannot connect to WMI"
}
# Output time of query

$datetime = get-date -uformat "%d/%m/%Y %H:%M:%S"
$UTC = get-date -uformat "%Z"
$querytime = $datetime + " UTC " + $UTC
# Check amount of installed RAM

if ($Online -eq $true -and $ConnectViaWmi -eq $true)
{
$colItems = get-wmiobject -class "Win32_ComputerSystem" -namespace "rootCIMV2" -computername $DC.Name
foreach ($objItem in $colItems)
{
$DCRAM = [math]::round($objItem.TotalPhysicalMemory/1024/1024, 0)
}
}
elseif ($Online -eq $false)
{
$DCRAM = "Cannot query - Ping timeout"
}
elseif ($ConnectViaWmi -eq $false)
{
$DCRAM = "Cannot connect to WMI"
}
# Query CPU information

if ($Online -eq $true -and $DCOS -notlike "*2003*" -and $ConnectViaWmi -eq $true)
{
$CPUproperty = "maxclockspeed", "numberOfCores", "NumberOfLogicalProcessors"
$DCCPUSpeed = Get-WmiObject -class "win32_processor" -Property $CPUproperty -computername $DC.Name -filter "deviceid='CPU0'" | Select-Object -expand "maxclockspeed"
$Win32_cpu = Get-WmiObject -class win32_processor -computername $DC.Name
$DCCPULogical = ($Win32_cpu | measure-object).count
$DCCPUCores = ($Win32_cpu | measure-object NumberOfCores -sum).sum
}

elseif ($Online -eq $true -and $DCOS -like "*2003*" -and $ConnectViaWmi -eq $true)
{
$CPUproperty = "maxclockspeed"
$DCCPUSpeed = Get-WmiObject -class "win32_processor" -Property $CPUproperty -computername $DC.Name -filter "deviceid='CPU0'" | Select-Object -expand "maxclockspeed"
$physCount = new-object hashtable
$Win32_cpu = Get-WmiObject -class win32_processor -computername $DC.Name
$Win32_cpu |%{$physCount[$_.SocketDesignation] = 1}
$DCCPULogical = $physCount.count
$DCCPUCores = ($Win32_cpu | measure-object).count
}

elseif ($Online -eq $false)
{
$DCCPUSpeed = "Cannot query - Ping timeout"
$DCCPUCores = "Cannot query - Ping timeout"
$DCCPULogical = "Cannot query - Ping timeout"
}

elseif ($ConnectViaWmi -eq $false)
{
$DCCPUSpeed = "Cannot connect to WMI"
$DCCPUCores = "Cannot connect to WMI"
$DCCPULogical = "Cannot connect to WMI"
}
# Query timezone information

if ($Online -eq $true -and $ConnectViaWmi -eq $true)
{
$DCTZ = Get-WmiObject -class "Win32_TimeZone" -computername $DC.Name | Select-Object -expand "Caption"
}
elseif ($Online -eq $false)
{
$DCTZ = "Cannot query - Ping timeout"
}
elseif ($ConnectViaWmi -eq $false)
{
$DCTZ = "Cannot connect to WMI"
}

# Query free disk space on C drive

if ($Online -eq $true -and $ConnectViaWmi -eq $true)
{
$Cdisk = Get-WmiObject Win32_LogicalDisk -ComputerName $DC.Name -Filter "DeviceID='C:'" | Select-Object FreeSpace
$Cdisk.FreeSpace = $([Math]::Round($Cdisk.FreeSpace/1073741824,1))
$DCDiskFree = $Cdisk.FreeSpace
}
elseif ($Online -eq $false)
{
$DCDiskFree = "Cannot query - Ping timeout"
}
elseif ($ConnectViaWmi -eq $false)
{
$DCDiskFree = "Cannot connect to WMI"
}

# Check if SCCM client is installed

if ($Online -eq $true -and $ConnectViaWmi -eq $true)
{
$SCCMCheck = get-wmiobject -namespace rootcimv2 -computername $DC.Name -class win32_process -filter 'Name="ccmexec.exe"'

if (-not $SCCMCheck)
{
$DCSCCMClient = "No"
}
else
{
$siteCode = (Get-WmiObject -computername $DC.Name -namespace rootccmpolicymachine -Class CCM_SystemHealthClientConfig).SiteCode
$DCSCCMClient = "Yes - " +$siteCode
}
}
elseif ($Online -eq $false)
{
$DCSCCMClient = "Cannot query - Ping timeout"
}
elseif ($ConnectViaWmi -eq $false)
{
$DCSCCMClient = "Cannot connect to WMI"
}

# Check if SCOM client is installed

if ($Online -eq $true -and $ConnectViaWmi -eq $true)
{
$SCOMCheck = get-wmiobject -namespace rootcimv2 -computername $DC.Name -class win32_process -filter 'Name="HealthService.exe"'

if (-not $SCOMCheck)
{
$DCSCOMClient = "No"
}
else
{

$Path = "hklm:SOFTWAREMICROSOFTMICROSOFT OPERATIONS MANAGER3.0AGENT MANAGEMENT GROUPS"
$baseKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey("LocalMachine", $DC.Name)
$s = ""

## Open the key
$key = $baseKey.OpenSubKey("SOFTWAREMICROSOFTMICROSOFT OPERATIONS MANAGER3.0AGENT MANAGEMENT GROUPS")

## Retrieve all of its children
foreach($subkeyName in $key.GetSubKeyNames())
{
## Open the subkey
$subkey = $key.OpenSubKey($subkeyName)
$returnObject = [PsObject] $subKey
$returnObject | Add-Member NoteProperty PsChildName $subkeyName | Select PSChildName

## Output the key
$s += $returnObject.PsChildName + " "

## Close the child key
$subkey.Close()
}
## Close the key and base keys
$key.Close()
$baseKey.Close()

$DCSCOMClient = "Yes - " +$s
}
}
elseif ($Online -eq $false)
{
$DCSCOMClient = "Cannot query - Ping timeout"
}
elseif ($ConnectViaWmi -eq $false)
{
$DCSCOMClient = "Cannot connect to WMI"
}
[array] $DomainDCs += $DC.HostName
$Online = $false
# Create object to collect elements

$OutputObj = New-Object -TypeName PSObject -Property @{
"Name" = $DC.Name.ToUpper()
"Description" = $DCDesc
"Ping Status" = $DCPing
"FQDN" = $DCFQDN
"IP Address" = $DCIPv4
"Operating System" = $DCOS
"Service Pack" = $DCOSSP
"Domain" = $DCDomain
"GC" = $DCGC
"FSMO Roles" = $DCFSMO
"AD Site" = $DCSite
"Read Only" = $DCRO
"LDAP Port" = $DCLDAP
"SSL Port" = $DCSLDAP
"Roles Installed" = $DCRoleOutput
"Last Boot Time" = $LastBoot
"Virtual" = $DCVM
"DNS Servers" = $DNSServers
"RAM (MB)" = $DCRAM
"CPU Speed (MHz)" = $DCCPUSpeed
"CPU Cores" = $DCCPUCores
"Logical CPUs" = $DCCPULogical
"Timezone" = $DCTZ
"Free space (C: GB)" = $DCDiskFree
"SCCM Client" = $DCSCCMClient
"SCOM Client" = $DCSCOMClient
"Query Time" = $querytime
} | Select-Object "Name","Description","Ping Status","FQDN","IP Address","Operating System","Service Pack","Domain","GC","FSMO Roles","AD Site","Read Only","LDAP Port","SSL Port","Roles Installed","Last Boot Time","Virtual","DNS Servers","RAM (MB)","CPU Speed (MHz)","CPU Cores","Logical CPUs","Timezone","Free space (C: GB)","SCCM Client","SCOM Client","Query Time"
# Add item to report

$report += $OutputObj

$Progress

# End of for each Domain Controller

}
# Export information to specified CSV file

$report | Export-Csv $FileLocation -Force -NoTypeInformation

Write-host "`n"
Write-Host "CSV file creation complete...."

# End of if CSV section

}

##########################################################
# End of CSV section
##########################################################
# Output domain controller count to screen

if ($SpecificDC -ne $null)
{
Write-host "`n"
$DCCount = $DomainDCs.Count
$DomainDCs = $DomainDCs | sort
Write-Host "Found $DCCount DCs in $DomainDNS. Displaying all DCs in the domain :" `r
Write-host "`n"
$DomainDCs
Write-host "`n"
}

 

 

 

February 2 2011

SCCM report to count enabled users in every domain

I needed a SCCM report to count all enabled users in every domain. This is different to the builtin ‘Count users by domain’ as that one only lists domain users that have logged onto a system (that one is from v_R_System).

Query =

SELECT Windows_NT_Domain0, count(*)
FROM
v_R_User
WHERE User_Account_Control0 = '512'
GROUP BY Windows_NT_Domain0
Order by Windows_NT_Domain0

While I am here, I may as well list 2 other reports that were useful to count all enabled computers in every domain, one report for workstations and one for servers:

SELECT Resource_Domain_OR_Workgr0, count(*)
FROM
v_R_System
WHERE Operating_System_Name_and0 LIKE '%workstation%' AND Resource_Domain_OR_Workgr0 NOT LIKE ''
GROUP BY Resource_Domain_OR_Workgr0
Order by Resource_Domain_OR_Workgr0

SELECT Resource_Domain_OR_Workgr0, count(*)
FROM
v_R_System
WHERE Operating_System_Name_and0 LIKE '%server%' AND Resource_Domain_OR_Workgr0 NOT LIKE ''
GROUP BY Resource_Domain_OR_Workgr0
Order by Resource_Domain_OR_Workgr0