Powershell method for finding any services that are set to start automatically but have been stopped due to a failure or error.

Scenario: You want a Powershell  method for finding any services that are set to start automatically but have stopped in error or by failure.

Solution:  The script below looks for any Exchange servers that start with 2013* and then uses the logic “Find a Service that is set to Automatic that is currently not running and an Exit Code of the service is not 0” for each server.  Then attempt to restart that service on each server.   An exit code of 0 means the service was stopped manually OR stopped by Windows as it was no longer required to run. Here is a list of Error Code/Exit Code descriptions: Exit Code Descriptions

 

#Collect Servers into a Variable
$1 = Get-exchangeserver 2013*

#Collect Services that are not started due to failure or error
$2 = $1 |%{Get-CimInstance win32_service -Filter "startmode = 'auto' AND state != 'running' AND Exitcode !=0 " -ComputerName $_ | select systemname, name, startname, exitcode}

#View the Services that are stopped for each server
$2

#Restart each failed service
$2 | %{Get-service $_.Name -computername $_.SystemName | Start-service -passthru}

Cannot access the C$ on one of your Windows Server 2012 servers

Scenario:  Your server is experiencing networking issues that appear local to the Server OS.  The symptoms experienced:

  1. Although you can successfully ping the server, you cannot access the c$ or other shares hosted off the server. Your error message talks about not having the appropriate permissions AND/OR the server not being available on the network.
  2. Although you can see the network adapters in Device Manager, you cannot see the network adapters in the Network & Sharing center via control panel.

Cause:  Network Adapter Corruption

Solution:  Uninstalling and Reinstalling the network driver on the server.  Below are other troubleshooting steps that may help:

Our Troubleshooting Steps:

  1. We found EventID 10016 in the System Log.  (Microsoft-Windows-DistributedCOM)
  2. We started testing if there is corruption with the Config Key. We  deleted the Config key from the registry: HKLM/System/currentcontrolset/Control/Network/Config ,config.  This key holds all of the Network card information. Once you reboot, it creates a new key in same registry with proper settings.
  3. After reboot we found that the config key was there ,but the server lost network connection completely.
  4. We tried assigning static IP using netsh via the command prompt but that resulted in the error: Element not found.
  5. That made us believe that the network database is corrupted.
    We uninstalled the Network Drivers and network card from device manager rebooted the server.
  6. Installed the new drivers back that resulted in server to function properly.

Checking Digital Signatures of a specific file against multiple servers

Scenario:  The other day an article was written by ARS Technica on a mail server attack that steals massive number of passwords. One of the symptoms is finding an unsigned OWAAuth.DLL and in some cases the file was located in a different directory.

Solution: Here is a quick way to check all of your Exchange servers to make sure all of your OWAAUTH.DLL files are signed and in the correct path:

#Build your Servers Variable
$Servers = Get-exchangeserver
#Build your Auth Variable
$Auth = $Servers |  %{Get-childitem -path "\$_c$program filesMicrosoftExchange Serverv15" -filter owaauth.dll -recurse | Get-authenticodeSignature}
#Export your Auth Variable to read it in Excel
$Auth | Export-csv C:tempAuth.csv

 

Use PowerShell to determine lastbootup time of a server or multiple servers

scenarios:  You want to quickly determine the bootup time for your Exchange Servers via Powershell.

Resolution: Run the following:

#For a Single Server:
Get-WmiObject win32_operatingsystem -computername ExSvr1 | select csname, @{LABEL='LastBootUpTime';EXPRESSION={$_.ConverttoDateTime($_.lastbootuptime)}}


#For Multiple Servers:
$1 = Get-ExchangeServer ExSvr*
$1 | %{Get-WmiObject win32_operatingsystem -computername $_.name | select csname, @{LABEL='LastBootUpTime';EXPRESSION={$_.ConverttoDateTime($_.lastbootuptime)}}}

Use PowerShell to search through multiple log files for specific text and export the results

Scenario:  You have multiple log/txt files you need to search through for specific text.  You would like to export/dump the text into another file.

Solution:  Run the following PowerShell Script.  Note the pattern contains the word you are looking for.  Unlike the “FIND” function in the command prompt, the PowerShell search does not require an exact case sensitive match.

#Look for any lines that has a text Pattern of "Fail" on it.
$1 = Get-ChildItem c:Temp*.log | Select-String -Pattern "Fail"

#For each line, export it to a csv.
$1 | Select line | Export-csv C:temptestline.csv

Disconnect RDP sessions via PowerShell

Scenario:  You are about to start maintenance on your servers and you want to remove any existing RDP session whether active of disconnected.  You want a quick way of doing this on all of your Exchange servers.

Solution:  Download the PSTerminalServices module from: https://psterminalservices.codeplex.com

Once download and installed, copy the PSTerminalServices folder from the install path into C:windowssystem32WindowsPowerShellv1.0.  Then run the following script in Exchange Powershell:

#Imports Terminal Services module
import-module psTerminalServices 

#Collect each Exchange Server in a variable
$Servers = Get-exchangeserver Ex2013*

#Now loop it to remove any existing TS Session.
$servers | %{
$Sessions = get-tssession -computername $_.name | where {($_.useraccount -like "domainname*")}
$sessions
$sessions | %{Stop-TSSession $_.sessionid -force}
}

 

 

Copy and then Rename files via PowerShell

Scenario:  You want to collect logs from various servers and place the copied logs into a single directory.  Due to the log names being the same on each server, we want avoid overwriting existing logs. We also want to know the server from where each log was copied from.

Solution:  The following will copy the IMAP logs from 4 servers into 1 local directory. Each file when copied to the directory will be renamed by prefixing the file with the server name.  It will also add the counter to the end of the file.

$Servers = "ExSvr1","ExSvr2","ExSvr3","ExSvr4"
$servers | %{$File = Get-ChildItem -Path "\$_c$Program FilesMicrosoftExchange ServerV15LoggingIMAP4" -Recurse;$i=1;Foreach ($f in $File) {Copy-Item $f.FullName ("C:TempIMAPPOP$_" + $f.BaseName + $i +".log");$i++}}
#End

 

 

 

Installing updates manually once approved via Configuration Manager and checking the install status for each server remotely

Scenario:  You use Microsoft System Center 2012 Configuration Manager to receive updates for Windows.  Once your updates are approved for installation, you can use the following script to perform a manual install. Once the manual install is kicked off from a remote machine, you can use additional PowerShell commands to determine the statuses for each update.

Here is a copy of the script we are using that is located on each one of our servers.  Reference to the script found here.

InstallUpdates.PS1

$MissingUpdates = Get-WmiObject -Class CCM_SoftwareUpdate -Filter ComplianceState=0 -Namespace rootCCMClientSDK 

$MissingUpdatesReformatted = @($MissingUpdates | ForEach-Object {if($_.ComplianceState -eq 0){[WMI]$_.__PATH}}) 

$InstallReturn = Invoke-WmiMethod -Class CCM_SoftwareUpdatesManager -Name InstallUpdates -ArgumentList (,$MissingUpdatesReformatted) -Namespace rootccmclientsdk 

$objCurrentPSProcess = [System.Diagnostics.Process]::GetCurrentProcess();

Stop-Process -Id $objCurrentPSProcess.ID;

 

To kick this script off remotely on your servers, you can use a similar PowerShell command such as:

Invoke-Command { powershell.exe -executionpolicy unrestricted C:updatesInstallUpdates.ps1} -ComputerName Win2012Svr1

OR, to run against multiple servers at once… Lets Loop It!

$Servers = Get-ExchangeServer Win2012Svr*

$Servers | %{Invoke-Command { powershell.exe -executionpolicy unrestricted C:updatesInstallUpdates.ps1} -ComputerName $_}

Instead of using Software Center to check the status of your updates via an RDP session to multiple servers,  lets use PowerShell again to invoke a command that will return the EvaluationState for each update:

Invoke-Command -computername Win2012Svr1 -scriptblock {Get-WmiObject -Class CCM_SoftwareUpdate -Namespace rootCCMC
lientSDK | Group EvaluationState}

OR against multiple servers, Lets loop it again!

$Servers = Get-ExchangeServer Win2012Svr*

$Servers  | %{Invoke-Command -computername $_ -scriptblock {Get-WmiObject -Class CCM_SoftwareUpdate -Namespace rootCCMClientSDK | Group EvaluationState}}

Below is what we determined each status represents.  Obviously there are some numerical codes missing, but these are the normal status codes we occasionally see:

0 = Not Started
5 = Downloading
6 = Waiting to Install
7 = Installing
8 = Requires Restart
13 = Failed

To restart the computers remotely, you can issue the following PowerShell Commands:

Restart-Computer Win2012Svr1 -force

or multiple servers:

$Servers = Get-ExchangeServer Win2012Svr*

$Servers  | Restart-computer -force

Happy updating!

 

 

 

 

 

 

Compare 2 powershell variable arrays and show values that do not match.

Scenario:  When performing a migration, we noticed a discrepancy in the  count of users that are in a distribution group compared to the count of users that have move requests (the move requests  were originally generated from that distribution group).  We have to determine which mailboxes are missing.

Resolution: Here is a quick way of comparing those 2 lists:

1. Pull the Distribution Group Members into a Variable:

$1 = Get-DistributionGroupMember Migration_710 | Select Alias

2. Pull the Move Requests that were batch into a second Variable:

$2 = Get-MoveRequest -batchname Migration_710 | Select Alias

3. Export both of those Aliases into a CSV file:

$1 | export-csv C:1.csv

$2 | export-csv C:2.csv

4. Import those csv back into new variables :

$file1 = Import-csv C:1.csv

$file2 = Import-csv C:2.csv

5. Compare the lists by running the following command.  The output should be the missing objects.

compare-object $file1 $file2

Commands to Create Mount Points from Unallocated Hard Drives

Scenario: You added new Hard Drives into your Windows Servers and you wish to  quickly partition these disks to be used as mount points. You can use the commands below to script it.

Commands:  We will be using DiskPart in order to accomplish this.

1. Open DiskPart: 

From a command prompt or powershell, type in diskpart and press enter.  A new DiskPart window should open up.

2. Determine the Disk Numbers of the newly installed disks:

List Disk 

3. Use the Disk Number  and use the commands below.  We are going to use Disk Number 3 as the newly installed disk. You can copy all the commands below at once and paste the commands into the DiskPart command window.

Select Disk 3
Create Partition Primary
Select partition 1
format  quick fs=ntfs Label=”MountPoint1″
Assign Mount=C:MountPoint1