Dec 24

Restart Computers in Sequential Order

Restarting servers is a necessary evil in a Windows administrator’s world.  Unfortunately, you cannot not always just restart servers during maintenance as they may have a service dependent on another server.  Due to this, you may need to restart your servers in sequential order.  Luckily, powershell 3.0 makes this quite easy using the restart-computer commandlet.  Please note, the restart-computer commandlet added several important parameters vs the 2.0 version, which includes the following (Good Explanation Here):

  • -Delay
  • -For
  • -Timeout
  • -Wait

The above parameters allow you to ensure a server rebooted before moving on in the script.  For a full description, see Restart-Computer on TechNet

For our script, we will use a CSV file that lists the server names and the sequence to group them for restarting (Yes we can have multiple servers in the same sequence number).  Our powershell script will then read in the the servers.csv, group the servers by their sequence number, and reboot the servers according to the sequence number group.  The below powershell script will wait until the servers have fully rebooted before moving to the next sequence number to reboot.  You may wish to modify the restart-computer parameters to suit your needs.  Additionally, you will need to modify the $filePath and $creds variables accordingly.

SERVERS.CSV

SERVER,SEQUENCE
ad1,1
ad2,2
web,2
sql,2
printers,3
files,3
app,4

 RESTART_SEQUENTIAL_ORDER.PS1

#=========================================================================
# Restart_Sequential_Order.ps1
# VERSION: 1.0
# AUTHOR: Brian Steinmeyer
# EMAIL: sigkill@sigkillit.com
# WEB: http://sigkillit.com
# DATE: 12/24/2014
# REQUIREMENTS:
# 1) Powershell 3.0 for the following parameters:
#    -Delay
#    -For
#    -Timeout
#    -Wait
# COMMENTS: This script restarts servers in sequential order and does not
# not start the next sequence until the previous server(s) rebooted.
#=========================================================================
 
# ------ SCRIPT CONFIGURATION ------
$filePath = "servers.csv"
$creds = get-credential domain\user
# ------ END CONFIGURATION ------
$data = Import-Csv $filePath 
$objdata = $data | Select SERVER,SEQUENCE | Group SEQUENCE | Select @{n="SEQUENCE";e={$_.Name}},@{n="SERVER";e={$_.Group | ForEach{$_.SERVER}}} | Sort SEQUENCE
ForEach ($d in $objdata) {
	$sequence = $d.SEQUENCE.ToString()
	$server = $d.SERVER.ToString()
	write-host "SEQUENCE: $sequence"
	write-host "------------"
	write-host "Rebooting: $server"
	restart-computer -ComputerName "$server" -Force -Wait -Credential $creds
}

 

Apr 04

365Licenses.ps1

#=========================================================================
# 365Licenses.ps1
# VERSION: 1.0
# AUTHOR: Brian Steinmeyer
# EMAIL: sigkill@sigkillit.com
# WEB: http://sigkillit.com
# DATE: 4/4/20114
# REQUIREMENTS:
# 1) Microsoft Online Services Sign-In Assistant for IT Professionals
# -(http://www.microsoft.com/en-gb/download/details.aspx?id=28177)
# 2) Windows Azure Active Directory Module for Windows PowerShell
# -(http://technet.microsoft.com/en-us/library/jj151815.aspx#bkmk_installmodule)
# COMMENTS: This script is intended to retrieve Office 365 licensing information
# by accepted domains. It will provide the active license count by domain,
# estimate the cost per domain, and provide the number of unused licenses.
#=========================================================================

# ------ SCRIPT CONFIGURATION ------
# Define License Unit Cost
$intCost = 3.88
# ------ END CONFIGURATION ------

# Connect to Microsoft Online
write-host "Connecting to Office 365..."
Import-Module MSOnline
Try {
Connect-MsolService -ErrorAction Stop
} Catch {
Write-Host $error[0].Exception -ForegroundColor Red -BackgroundColor Black
Write-Host "Error Connecting to Office 365... Quitting Script!" -ForegroundColor Red -BackgroundColor Black
Break
}

# Get Office 365 Accepted Domains and Active User Licenses
Try {
$arrDomains = @(Get-MsolDomain)
} Catch {
Write-Host "Error Retrieving Office 365 Accepted Domains... Quitting Script!" -ForegroundColor Red -BackgroundColor Black
Break
}
$arrCompany = @()
$TotalLicenses = 0
$TotalCost = 0
foreach ($d in $arrDomains){
$domain = $d.Name
write-host ("PROCESSING: " + $domain.ToUpper())
$users = Get-MsolUser -All | where {$_.isLicensed -eq "True" -and $_.UserPrincipalName.Contains($domain)} | Select DisplayName, UserPrincipalName -ExpandProperty Licenses | Select DisplayName, UserPrincipalName, AccountSkuID
If ($users.count -ne $null){
$i = $users.count
$users | format-table
$users | Export-Csv ("365_Licenses_" + $domain.replace(".","_") + ".csv")
}
Else{
$i = 0
Write-Host "0 Licenses<code>n</code>n"
}
$objCompany = New-Object -TypeName PSObject
$objCompany | Add-Member -Name 'Domain' -MemberType Noteproperty -Value $domain
$objCompany | Add-Member -Name 'Licenses' -MemberType Noteproperty -Value $i
$objCompany | Add-Member -Name 'Cost' -MemberType Noteproperty -Value ("{0:C2}" -f ($i * $intCost))
$arrCompany += $objCompany
$TotalLicenses += $i
$TotalCost += ($i * $intCost)

}

# Get Company Licensing Info
Try {
$companyLicenses = Get-MsolAccountSku | Select AccountSkuId, ActiveUnits, WarningUnits, ConsumedUnits
} Catch {
Write-Host $error[0].Exception -ForegroundColor Red -BackgroundColor Black
Write-Host "Error Retrieving Office 365 Account Info... Quitting Script!" -ForegroundColor Red -BackgroundColor Black
Break
}
$objCompany = New-Object -TypeName PSObject
$objCompany | Add-Member -Name 'Domain' -MemberType Noteproperty -Value "TOTAL ACTIVE LICENSES"
$objCompany | Add-Member -Name 'Licenses' -MemberType Noteproperty -Value $TotalLicenses
$objCompany | Add-Member -Name 'Cost' -MemberType Noteproperty -Value ("{0:C2}" -f $TotalCost)
$arrCompany += $objCompany

$unusedLicenses = ($companyLicenses.ActiveUnits - $companyLicenses.ConsumedUnits)
$unusedCost = ($unusedLicenses * $intCost)
$objCompany = New-Object -TypeName PSObject
$objCompany | Add-Member -Name 'Domain' -MemberType Noteproperty -Value "TOTAL UNUSED LICENSES"
$objCompany | Add-Member -Name 'Licenses' -MemberType Noteproperty -Value $unusedLicenses
$objCompany | Add-Member -Name 'Cost' -MemberType Noteproperty -Value ("{0:C2}" -f $unusedCost)
$arrCompany += $objCompany

$objCompany = New-Object -TypeName PSObject
$objCompany | Add-Member -Name 'Domain' -MemberType Noteproperty -Value "GRAND TOTAL LICENSES"
$objCompany | Add-Member -Name 'Licenses' -MemberType Noteproperty -Value $companyLicenses.ActiveUnits
$objCompany | Add-Member -Name 'Cost' -MemberType Noteproperty -Value ("{0:C2}" -f ($companyLicenses.ActiveUnits * $intCost))
$arrCompany += $objCompany

# Display Statistics
$companyLicenses | Format-Table -Auto
$arrCompany | Format-Table -Auto

 

Oct 08

Modify Proxyaddresses Domain

This powershell snippet is used to replace a domain in all values in a user’s proxyAddresses attribute.  It requires using Microsoft’s ActiveDirectory module.  It is is capable of bulk modifying all users in an OU or can modify a single user if you specify their DN.  In the script below, modify the SearchBase and replace @olddomain.com and @newdomain.com.

Import-Module ActiveDirectory
Get-ADUser -Filter * -SearchBase 'OU=Test,DC=domain,DC=local' -Properties proxyaddresses | Foreach {Set-ADUser -identity $_ -Replace @{'ProxyAddresses' = @($_.proxyaddresses -Replace "@olddomain.com","@newdomain.com")}}