Monday, July 25, 2016

Find all accounts that have their password set to never expire

This guy was written to address accounts that are in violation of policy.  Password set to never expire is an easy dig on an audit for auditors.  I run this every 90 days and investigate where needed.  Once the investigation is complete and all exceptions are approved any object leftover gets its password set to (PasswordNeverExpires -eq $False).

Get-ADUser -filter { Enabled -eq $True -and PasswordNeverExpires -eq $True } –Properties * |Select-Object Name, SAMAccountName, Title, Enabled, WhenCreated, WhenChanged, PasswordNeverExpires, Description | Export-Csv 'C:\temp\Pass_Never_Expires.csv' -NoTypeInformation –NoClobber


You can always run this as a scheduled task and email it to yourself.  That info can be found here: http://mytechnicalsolution.blogspot.com/search/label/send-MailMessage

Monday, July 18, 2016

Ping a list of servers

Ever get tired of being given a list of servers to do something with and more than a handful are offline or have been retired?  I am, so I decided to write this quickie to validate which machines are online and which are not.  Depending on the number of servers in your list this process can take a few to complete.

The script below will return just the machines that responded.

$Computers = Get-Content C:\temp\Servers_Names.txt; Test-Connection $Computers -ErrorAction SilentlyContinue -Count 1 | Select-Object Address,IPv4Address,ResponseTime,BufferSize

This one will provide the results to a text file.

$Computers = Get-Content C:\temp\Servers_Names.txt; Test-Connection $Computers | Out-File C:\temp\Ping_Results.txt

And alternatively this script will just provide a count of how many can ping and how many can’t.


$computers = Get-Content C:\temp\Servers_Names.txt; $Computers | group {test-connection -count 1 -ComputerName $_ -quiet} | Sort-Object Name -Descending


Example:
  Count Name                    Group                                                                                                                                                                                                                            
  -----      ----                         -----                                                                                                                                                                                                                            
  14        True                      {Server1, Server2Server3Serve...}                                                                                                                                                                                    
  4          False                     {Server15Server16Server17, Se...                                                                                                                                                                 

Monday, July 11, 2016

Finding all DNS servers in the domain

Learning a new environment is tough sometimes, not wanting to be the new guy asking all the questions.  One of the things I wrote to help me gather information without asking or giving me enough information to ask an intelligent question was the script below.  It was written specifically to find servers running the DNS service but can be modified easily to find any service running on windows servers in your domain.

Originally I wrote the script like this:

Get-ADComputer -Filter {OperatingSystem -Like "Windows *Server*"} -Property *  | foreach { Get-Service -name "DNS" -ComputerName $_.Name -ErrorAction SilentlyContinue | Select-Object -Property MachineName,ServiceName,Status }

But kept erroring out. Exact error:

Get-ADComputer : The server has returned the following error: invalid enumeration context. 

I googled some and found this: 


So I followed the script modification recommendations and ended up with this:

$adobjects = Get-ADComputer -Filter {OperatingSystem -Like "Windows *Server*"} -Property *; $adobjects = | foreach { Get-Service -name "DNS" -ComputerName $_.Name -ErrorAction SilentlyContinue | Select-Object -Property MachineName,ServiceName,Status } 

The script ran to completion without error.  If you want to export to CSV add this to the end of the script.

| Export-CSV "C:\temp\DNS_Servers.csv" -NoClobber -NoTypeInformation


Just so you know, depending on the number of server in your domain this script can take a while to complete, but it does complete.

Monday, July 4, 2016

Ensure all accounts in the Disabled Accounts OU are Disabled

I noticed the help desk was enabling accounts and leaving them in the disabled accounts OU.  We have user based policies that get applied based on your departmental OU.  By not moving the account to the correct departmental OU these policies don’t get applied.  Causes user issues like drive mappings and printer mappings don’t get applied.  After talking with the manager of the help desk who discussed it with their team nothing changed.  This laziness caused un-necessary calls to the help desk where the help desk technician manually mapped drives and printers.  This extra work circumvented our standard process and needed to be fixed so I wrote this.

This script runs multiple times a day and disables every account in the disabled accounts OU.  Once I put this in place and communicated this was happening and should be zero impact to our customers as long as the help desk preformed their job correctly my standards were now being followed.

Start of script

###############################################################################
#  Script Name:   Disable_User_Accounts_in_Disabled_Accounts_OU.ps1
#  Created On:    02/26/2014
#  Author:        Joshua
#  Purpose:       Ensure all accounts in the Disabled Accounts OU are Disabled                                               
#  Last Modified: 04/28/2016
#  Last Modifier: Joshua
###############################################################################

Get-ADUser -Filter 'name -like "*"' -SearchBase "OU=Disabled Accounts,DC=YourDomain,DC=com" | Disable-ADAccount


End of script

Sunday, July 3, 2016

Domain Replication Report

Years ago I would for a company that felt it needed a domain controller at every remote location against the advice of all of the employed SEs and SAs.  This caused some issues being that there were 90 domain controllers in the domain.  On an almost daily basis we had domain controllers go off line and start the 60 count down to tombstone.  So to make sure my co-workers were doing their job I wrote this to prevent a forced rip out of a tomb-stoned domain controller.  The original script was very simple only running RepAdmin.  Since then I have put in some additions like dcddiag.  It also will provide a list of machines that are currently in the computers container.  As you may know no group policies can be applied to these machines.  This was an addition so I could keep the helpdesk honest.  Hope this helps.

###############################################################################
#  Script Name:   Domain_Replication_Summary.ps1
#  Created On:    02/15/2009
#  Author:        Joshua & Matthew
#  Purpose:       Get Replication Summary and email to a group                                                     
#  Last Modified: 02/15/2016
#  Last Modifier: Joshua
###############################################################################


#Import-Modules
Import-Module ActiveDirectory
Add-PSSnapin Quest.ActiveRoles.ADManagement

#Variables
$date = Get-Date -Format yyyyMMdd
$aging = (Get-Date).adddays(-8).ToString("yyyyMMdd")
$aging2 = (Get-Date).adddays(-8).ToString("yyyyMMdd")
$log      = "C:\ST_Logs\Replication_Summary_Report_'$date'.txt"
$log2      = "C:\ST_Logs\DCDiag_Summary_Report_'$date'.txt"
$smtp = "YourSMTP.YourDomain.com"
$to = "Domain_Replication_Summary@ YourDomain.com "
$from = "DNR_Reports@ YourDomain.com "
$subject = "Domain Health Check $date"
$staging = dsquery computer "CN=Computers,DC=YourDomain,DC=com" -name *
$bodystart = "Please see attached logs.

Below computer accounts are in the Computers Container and need to be moved.
"
$body = $bodystart+$staging

# Run RepAdmin Commands
repadmin /replsummary | Out-File -FilePath $log
dcdiag /e /q /n:YourDomain.com | Out-File -FilePath $log2

# Remove all reports greater than 7 days old
Remove-Item "C:\PS_Scripts\Temp_Working\Replication_Summary_Reports\Replication_Summary_Report_'$aging'.txt" -recurse
Remove-Item "C:\PS_Scripts\Temp_Working\Replication_Summary_Reports\Replication_Summary_Report_'$aging2'.txt" -recurse
Remove-Item "C:\PS_Scripts\Temp_Working\Replication_Summary_Reports\DCDiag_Summary_Report_'$aging'.txt" -recurse
Remove-Item "C:\PS_Scripts\Temp_Working\Replication_Summary_Reports\DCDiag_Summary_Report_'$aging2'.txt" -recurse

#### Now send the email using \> Send-MailMessage

send-MailMessage -SmtpServer $smtp -To $to -From $from -Subject $subject -Body $body -BodyAsHtml -Priority normal -Attachments $log, $log2

Monitor MS Exchange

Years ago I needed a way to monitor Exchange.  When I say Exchange I mean all aspects of Exchange, total number of mail boxes, number of mailboxes per DB, DB size, DB white space, free space in the log drive, and last backup time. At the time I was doing a lot of this calculating manually until I found Steve Goodman's site http://www.stevieg.org/ and his PS1 “Get-ExchangeEnvironmentReport”.  This report is great, I have used it in every environment I have managed since 2009 at it has saved me countless hours of time not having to calculate everything in excel like I was in 2009.  If an MS Exchange report that provides a quick high level status of your mail cluster, then check out this report.


Document all VMs and their associated resources

So this one was out of necessity.  When I started my new job I quickly realized that our AV solution was used to lock out workstation directories like AppData and c:\temp.  These security settings meant I couldn’t run RVTools to document my virtual environment.  I have always pulled out data from VMware so I can monitor growth patterns and now I couldn’t use my process so I had to find another way.  That’s when I came up with the script below.  It’s not all the information RVTools would provide but it’s enough to understand growth and when to add hosts to the cluster.
 Start of script
 Connect-VIServer 'YourServer' -user YourDomain\YourUser -Password YourPassword
 Get-VMHost | Select-Object Name, State, ConnectionState, PowerState, VMSwapfileDatastoreId, VMSwapfilePolicy, ParentId, IsStandalone, Manufacturer, Model, NumCpu, CpuTotalMhz, CpuUsageMhz, LicenseKey, MemoryTotalMB, MemoryTotalGB, MemoryUsageMB, MemoryUsageGB, ProcessorType, HyperthreadingActive, TimeZone, Version, Build, Parent, VMSwapfileDatastore, StorageInfo, NetworkInfo, DiagnosticPartition, FirewallDefaultPolicy, ApiVersion, MaxEVCMode, CustomFields, ExtensionData, Id, Uid, Client, DatastoreIdList | Sort-Object Name | Export-Csv 'C:\temp\vCenter.csv' -NoClobber –NoTypeInformation
 Disconnect-VIserver * -confirm:$false
 End of script
 Also if you want to email the exported file you can use the send-MailMessage command.  That can be found here: http://mytechnicalsolution.blogspot.com/search/label/send-MailMessage

Get a list of all domain controllers in the domain

With a geographically dispersed team I wanted to make sure our domain controller naming convention was consistent across the domain.  So I wrote this:

Start of script

Get-ADGroupMember 'Domain Controllers' | foreach { Get-ADComputer -identity $_.name -Properties * | Select-Object Name, IPv4Address, DNSHostName }

End of script

A few months later I was asked by an auditor to provide a list of al the domain controllers in my environment so I added this to the end of the script.


| export-CSV 'C:\temp\Domain_Controllers.csv' -NoTypeInformation -NoClobber

Document all Windows Server in the Domain

At my last job my CIO would always call me asking “what does server x do?” when change control voting was taking place.  This was mostly because our naming convention in no way resembled what the purpose of each server was.  So I decided to create a CSV weekly via scheduled task that documented the name of each server, its OS, and IP.  But most importantly it pulled in the description field from the computer object.  I know some of you will have to go back through your server objects and add a description but this was well worth the time and it made my CIO feel like I did this to make their job easier.

I used the Get-ADComputer but I had to make sure I only pulled out server OS.  So, I had to add a filter based off of the OperatingSystem field. Example: {OperatingSystem -Like "Windows *Server*"}  So if you wanted to find all Windows XP machines, just change the filter. Example: {OperatingSystem -Like "Windows *XP*"}  But alternatively if you want to find all machines expect Windows XP just change the filter to {OperatingSystem -NotLike "Windows *XP*"}

Start of script

Get-ADComputer -Filter {OperatingSystem -Like "Windows *Server*"} -Property * | Select-Object -Property Name,Description,OperatingSystem,OperatingSystemServicePack,IPv4Address | Export-Csv '\\your share\Server_Inventory.csv' -NoTypeInformation -Encoding UTF8

End of script


You can also use the Send-MailMessage command to email the csv as an attachment.  The command can be found here: http://mytechnicalsolution.blogspot.com/search/label/send-MailMessage

Document members of an AD group and when the account last logged in

I wanted a process to identify the members of our domain admins group and see if that account was being used.   This was to see if any admin accounts were being orphaned.  I also provide this list when auditors ask for all the domain admins group members, but in reality this script can be used to audit any AD group.

Start of script

Get-ADGroupMember -Identity 'Domain Admins' | foreach { Get-ADUser -identity $_.SAMAccountName -Properties * | Select-Object name, @{Name="Password Last Set"; Expression={[DateTime]::FromFileTime($_.pwdLastSet)}}, LastLogonDate, @{Name="Last Logon Time Stamp"; Expression={[DateTime]::FromFileTime($_.lastLogonTimestamp)}} }

End of script

If you want to export this to CSV add this to the end.

| Export-Csv 'C:\temp\Domain_Admin_Members_and_Last_Logon.csv' -NoClobber –NoTypeInformation

You can also use the Send-MailMessage command to email the csv as an attachment.  The command can be found here: http://mytechnicalsolution.blogspot.com/search/label/send-MailMessage

Find inactive AD user accounts -- Last Logon Date

This is a script I run weekly to ensure user objects are not being left in AD to get stale.  I have used this script for a few years and it reminds me to follow up on stale objects.  If you wanted to you could end this script with a send-mail command and add the exported CSV to as an attachment.

Start of script

# 8/30/2013
# Pulls a list of users that have not logged in for the last 90 days

Remove-Item 'C:\temp\90day_no_logon.csv' -recurse


Search-ADAccount -AccountInactive -UsersOnly -TimeSpan 90.00:00:00 | Select-Object Name, Description, Enabled, LastLogonDate, SamAccountName, DistinguishedName | Sort-Object Name | Export-Csv 'C:\temp\90Day_No_Logon.csv' -NoClobber -NoTypeInformation

End of script

Send email from PowerShell and add an attachment -- send-MailMessage

In my role I am always running PowerShell routines daily or weekly to force accuracy in AD.  Whether its company naming convention or updating the manager field when new employees come aboard or old employees change roles I want to see what was updated to ensure my routine is still solid and not in need of any updates.  So I wrote this to be sure I can always find the information I need I email the change logs to myself at 6am so first thing in the morning I can verify my nightly process ran smooth.

#Variables
$log      = "location of the file you want to attach"
$smtp = "MailServer.YourDomain.com"
$to = "Recipents@YourDomain.com"
$from = "DNR_YourAddress@YourDomain.com"
$subject = "your subject"
$body = "Please see attached logs.

#”Your process that creates the file you want to email to a person or group goes on the next line”

#### Now send the email using \> Send-MailMessage

send-MailMessage -SmtpServer $smtp -To $to -From $from -Subject $subject -Body $body -BodyAsHtml -Priority normal -Attachments $log

Saturday, July 2, 2016

Force all VMs to check and update VMware tools at reboot

When I started my new job I noticed that most of the VMs were up to six versions behind in regards to VMware Tools.  I was having NIC stability issues and weird random lockups so I wanted to take a big swing at this issue.  I decided to google how to turn set the “ToolsUpgradePolicy” to "UpgradeAtPowerCycle".  Below is what I found and worked for me as is. For the record the VMware Tools upgrades did stabilize my VMs.

Start of script

connect-viserver -server "your server" -user “domain\user” -password “your password”

#Turn on auto update at next boot

Foreach ($v in (get-vm)) {
$vm = $v | Get-View
$vmConfigSpec = New-Object VMware.Vim.VirtualMachineConfigSpec
$vmConfigSpec.Tools = New-Object VMware.Vim.ToolsConfigInfo
$vmConfigSpec.Tools.ToolsUpgradePolicy = "UpgradeAtPowerCycle"
$vm.ReconfigVM($vmConfigSpec)
}

Disconnect-VIserver * -confirm:$false

End of script

Also though it was good to figure out how to turn this off if all hell breaks loose. 
Here it is:

Start of script

connect-viserver -server "your server" -user “domain\user” -password “your password”

#turn off auto update at next boot

Foreach ($v in (get-vm)) {
$vm = $v | Get-View
$vmConfigSpec = New-Object VMware.Vim.VirtualMachineConfigSpec
$vmConfigSpec.Tools = New-Object VMware.Vim.ToolsConfigInfo
$vmConfigSpec.Tools.ToolsUpgradePolicy = "manual"
$vm.ReconfigVM($vmConfigSpec)
}

Disconnect-VIserver * -confirm:$false

End of script

Documenting HBA Information with WWNs, PCI Bus, and Card Model

I decided to figure out how to document the HBAs and WWNs for all of my fiber channel connections on all of my standalone ESXi host.  This was a quick solution based off of a previous script I found and modified.  I used that same methodology to come up with this.

Start of script

Import-Csv C:\temp\ESXi_Server_Names.csv | foreach { 
  
Connect-viServer -server $_.Server -User root -Password “your password”

Get-VMHostHba | Select-Object VMHost,Status,Device,PCI,Model,NodeWorldWideName,PortWorldWideName | Format-Table * | Out-File C:\Temp\ESXi_HBA.txt -Width 300 -Append
               
                Disconnect-VIserver * -confirm:$false }


End of script

vSwitch Documentation with CDP Information

I was asked today to document all the vSwitches in all of my standalone ESXi host.  Initially I was going to log into each and document everything in excel but I knew there was a more efficient way.  So I started to google and got dozens of sites back and dug through them all and finally found one that worked for me.  I was able to run through one host at a time, but I wanted it to be better.  So I added an import and for each with some squiggly brackets then piped that out to a text file.  See below for full PowerCLI script with my modifications.  Original script before my changes can be found here: http://kunaludapi.blogspot.com

Start of script

 Add-PSSnapin VMware.VimAutomation.core 
 Add-PSSnapin VMware.VimAutomation.Vds 
  
Import-Csv C:\temp\ESXi_Server_Names.csv | foreach { 
  
 Connect-viServer -server $_.Server -User root -Password "your password"
   
 $Collection = @() 
  
 $Esxihosts = Get-VMHost | Where-Object {$_.ConnectionState -eq "Connected"} 
 foreach ($Esxihost in $Esxihosts) { 
   $Esxcli = Get-EsxCli -VMHost $Esxihost 
   $Esxihostview = Get-VMHost $EsxiHost | get-view 
   $NetworkSystem = $Esxihostview.Configmanager.Networksystem 
   $Networkview = Get-View $NetworkSystem 
      
   $DvSwitchInfo = Get-VDSwitch -VMHost $Esxihost 
   if ($DvSwitchInfo -ne $null) { 
     $DvSwitchHost = $DvSwitchInfo.ExtensionData.Config.Host 
     $DvSwitchHostView = Get-View $DvSwitchHost.config.host 
     $VMhostnic = $DvSwitchHostView.config.network.pnic 
     $DVNic = $DvSwitchHost.config.backing.PnicSpec.PnicDevice 
   } 
    
   $VMnics = $Esxihost | get-vmhostnetworkadapter -Physical 
   Foreach ($VMnic in $VMnics){ 
       $realInfo = $Networkview.QueryNetworkHint($VMnic) 
       $pNics = $esxcli.network.nic.list() | where-object {$vmnic.name -eq $_.name} | Select-Object Description, Link          
       $Description = $esxcli.network.nic.list() 
       $CDPextended = $realInfo.connectedswitchport 
         if ($vmnic.Name -eq $DVNic) { 
            
           $vSwitch = $DVswitchInfo | where-object {$vmnic.Name -eq $DVNic} | select-object -ExpandProperty Name 
         } 
         else { 
           $vSwitchname = $Esxihost | Get-VirtualSwitch | Where-object {$_.nic -eq $VMnic.DeviceName} 
           $vSwitch = $vSwitchname.name 
         } 
   $CDPdetails = New-Object PSObject 
   $CDPdetails | Add-Member -Name EsxName -Value $esxihost.Name -MemberType NoteProperty 
   $CDPdetails | Add-Member -Name VMNic -Value $VMnic -MemberType NoteProperty 
   $CDPdetails | Add-Member -Name vSwitch -Value $vSwitch -MemberType NoteProperty 
   $CDPdetails | Add-Member -Name Link -Value $pNics.Link -MemberType NoteProperty  
   $CDPdetails | Add-Member -Name PortNo -Value $CDPextended.PortId -MemberType NoteProperty 
   $CDPdetails | Add-Member -Name Device-ID -Value $CDPextended.devID -MemberType NoteProperty 
   $CDPdetails | Add-Member -Name Switch-IP -Value $CDPextended.Address -MemberType NoteProperty 
   $CDPdetails | Add-Member -Name MacAddress -Value $vmnic.Mac -MemberType NoteProperty 
   $CDPdetails | Add-Member -Name SpeedMB -Value $vmnic.ExtensionData.LinkSpeed.SpeedMB -MemberType NoteProperty 
   $CDPdetails | Add-Member -Name Duplex -Value $vmnic.ExtensionData.LinkSpeed.Duplex -MemberType NoteProperty 
   $CDPdetails | Add-Member -Name Pnic-Vendor -Value $pNics.Description -MemberType NoteProperty 
   $CDPdetails | Add-Member -Name Pnic-drivers -Value $vmnic.ExtensionData.Driver -MemberType NoteProperty 
   $CDPdetails | Add-Member -Name PCI-Slot -Value $vmnic.ExtensionData.Pci -MemberType NoteProperty 
   $collection += $CDPdetails 
   } 
 } 
  
 $Collection | Sort-Object esxname, vmnic | ft * | Out-File C:\Temp\ESXi_Net.txt -Width 300 -append
  
 Disconnect-VIserver * -confirm:$false }


End of script