PowerCLI – Function to Wait for Windows VM to Reboot

Sometimes VMWare Tools will report that a Windows VM is running before all the services are actually running.  I created the following simple PowerCLI function to poll for VMWare Tools status, then wait an extra 5 seconds before returning in order to ensure that all services are, in fact, operational:

wait-reboot VMName

function wait-reboot {
    $Go = $false

    While (!$Go) {
      $Go = $True
      $ToolsStatus = (Get-VM $VM | Get-View).Guest.ToolsStatus
        if ($ToolsStatus -ne "toolsOk") { $Go = $false}
        if ($ToolsStatus -eq "toolsOk") { $Go = $True}

      sleep 5

Powershell – Automating HP c7000 Virtual Connect Domain Configuration

In preparation for private cloud deployment, our HP c7000 BladeSystem Virtual Connect domain needed configuration.  Of course, the VCEM modules allow CLI interaction, so I figured I could automate the process using a script.  Problem is, the SSH buffer maxes out after about 50-60 lines from the script, resulting in catastrophic configurations.  As always, PowerShell has come to the rescue.  After downloading and installing the SSH Sessions module for PowerShell, I was able to convert my script into PowerShell to deliver the script to the VC module in a controlled (and programmatic!) fashion.  In my experiences, the script I provide below took about 40 minutes to complete, with most of the time consumed by importing the enclosure and creating all the server profiles.

Some assumptions:

Create Self-Signed Certificate for Windows

I ran into an issue with a Windows server that lost its self-signed certificate (the circumstances surrounding this event are embarrassing, and therefore, irrelevant).  I needed to recreate the self-signed cert in order to Remote Desktop to the machine, but could not find a lot of references on doing so after a moderately exhaustive search online.  I found some generic OpenSSL references to self-signed certs scattered around (none specific to Windows) and pulled them together below.  So, if you’re in need of a self-signed cert for a Windows server in order to RDP, follow the directions below.

PowerShell – Create High Volumes of VMs using Cloning

Sometimes you need to create and destroy a very high number of VMs in a short period of time (like when you’re testing out a new OS build).  I got tired of manually doing so in a vSphere environment, so I threw this little ditty together to help automate the process using PowerCLI.  The script first clones and starts an existing base build VM (with VMTools installed, which is a requirement; I tried to get away with not installing, but there was little point to this practice).  It will wait for the new VM to get an IP address (assigned via DHCP, also a requirement), connect the build media, run some scripts from the build media before disconnecting that media, and finally the VM will restart.  If the process fails at any point, it cleans up the failed VM.

Try {
  New-VM -Name Win12R2-testscan -Template Win21R2-CloneMe -VMHost VMHOST.CONTOSO.com
  Start-VM Win12R2-testscan

  while (!$ipaddress) {
    $ipaddress = (get-vm win12r2-testscan).guest.ipaddress[0]

  $cd = get-cddrive -VM win12r2-testscan
  Set-CDDrive -CD $cd -IsoPath "[ISOs] Win2012R2_Build.iso" -Connected:$true -Confirm:$False

  Invoke-VMScript -VM Win12R2-testscan -ScriptText "Copy-Item 'D:\*' 'C:\users\administrator\desktop' -Recurse ; cd C:\users\administrator\desktop ; C:\users\administrator\desktop\Start-Build.ps1" -GuestUser "administrator" -GuestPassword  "AdminPassword123"

  Set-CDDrive -CD $cd -nomedia -confirm:$False
  Restart-VMGuest -VM win12r2-testscan
Catch { Write-Warning "process failed" 
  Stop-VM -VM win12R2-testscan -Confirm:$false
  Remove-VM -VM Win12R2-testscan -DeletePermanently -Confirm:$false

PowerShell – Remote Session to Domain Controller

Sometimes you need to run Active Directory scriptlets in PowerShell, but logging into your DC takes too long, there are too many RDCs already, or you’re just lazy.  Regardless, the following script will allow you to initiate a remote PowerShell session to your DC and import the ActiveDirectory module, so you can perform AD administration on your workstation.  If this script is saved in your environment path (e.g. C:\Windows\System32), you can call it at anytime from PowerShell by just typing the script name (I called mine RemAD.ps1 and put it at the beginning of AD scripts as “.\RemAD.ps1″).  Obviously you will need to be logged in as a user that has login rights to the DC.  Also, you will need to login to your DC at least once and run Enable-PSRemoting in PowerShell before remote sessions are possible.

I should point out that this method adds the prefix “Rem” to your standard PowerShell scriptlets (e.g. you would call Get-RemADDomainController instead of Get-ADDomainController in your remote session).  The prefix is not necessary, but using it might reduce confusion.

$RemServer = "DC01"
$s = new-pssession -computer $RemServer
Invoke-Command -session $s -script { Import-Module ActiveDirectory }
Import-PSSession -session $s -module ActiveDirectory -prefix Rem

PowerShell – Roll Microsoft Print Cluster

In later releases of Microsoft’s print clustering service, moving the primary node of a cluster requires setting up dependencies correctly, otherwise, node splitting occurs.  Instead of fixing the improper cluster configuration, I wrote the following PowerShell script to roll each cluster group required to the standby node.  This script was written with a 2 node cluster in mind, so if there are more than 2 in your cluster, modification might be necessaary.  This script will only work on servers with clustering installed.

Import-Module FailoverClusters

$Nodes = Get-ClusterNode
$nodeowner = Get-ClusterGroup "PRINTCLUSTERNAME" | select ownernode
if ($nodeowner -eq $nodes[0].Name) { $clusternodename = $nodes[1].Name } else { $clusternodename = $nodes[0].Name }

Move-ClusterGroup "PRINTCLUSTERNAME" -node $clusternodename -wait 0
Move-ClusterGroup "cluster group" -node $clusternodename -wait 0
Move-ClusterGroup "Available Storage" -node $clusternodename -wait 0

PowerShell – New NetApp LUN

Sometimes you need a LUN quickly.  In cases like these, it’s helpful to be able to use PowerShell instead of NetApp’s GUI.  Fortunately, there is a way (requires downloading the NetApp DataOnTap PowerShell Module ver 3.0, which requires you to create an account and sign in).  The following script will create a Volume and LUN of the same size (NetApp best practice), turn on de-duplication for the volume, make both of them thin provisioned, and map an iGroup to the new LUN.

$naController = "FILER.CONTOSO.COM"
$volName = "ESXi_Vol_4"
$lunName = "ESXi_LUN_4"
$lunSize = "1T"
$iGroup = "ESXi"
$Username = "USERNAME"

Import-Module DataOnTap

Connect-NaController -Name $naController -Credential $Username

New-NaVol -Name $volName -Aggregate aggr1 -Size $lunSize
New-NaLun -Path /vol/$volName/$lunName -Size $lunSize -Unreserved #Create LUN and mark as thin provisioned

$volObj = Get-NaVol $volName

Set-NaVolOption $volObj.Name guarantee none #Thin Provision Volume
Enable-NaSis -path "/vol/$($volObj.name)" #Dedupe Volume

Set-NaLunSpaceReserved -path /vol/$volName/$lunName -off #Thin Provision LUN

Add-NaLunMap /vol/$volName/$lunName $iGroup

PowerShell – Install SCCM 2012 R2 Prerequisites

This is a fairly complicated script that will install the required prerequisites to install SCCM 2012 R2 on a server.  It was designed under the functional model in order to compartmentalize each step required, reducing the overall complexity.  The script requires media in order to complete successfully, detailed in the Script Media Requirements section below.  Each function of the script is then reviewed, in order to ensure proper use, as there are several overarching prerequisites in order for the script to work correctly.

Update to PowerShell Active Directory DC Health Check

This script is an update to a previous DC Health PowerShell script that requires the Quest AD module.  The below script does not require any additional modules to be installed but simply requires the ActiveDirectory module that is installed on any 2008 DC.  You can, of course, use a remote session to connect to your domain controller to perform this from your admin workstation.

Import-Module ActiveDirectory

#DC Log Archive location: \\COMPUTERNAME\c$\Windows\System32\winevt\Logs

#Routine to highlight errors in the script
filter colorize-row{
    [string]$prop="Free Space (%)") #Property of the table to highlight; must be exactly the same as defined in the hashtable below

    $fgc=[console]::ForegroundColor; #Save current console color

    #test to see if the drive free space is below 20%
    if ($_.$prop -lt 20) { [console]::ForegroundColor=$color; $_ } #Set the color to $color; then output the property string
    else{ $_ } #otherwise, just output the property string

    [console]::ForegroundColor=$fgc; # revert to saved console colors

#Get Forest DCs
$DCs = @() #Initialize the DC array
$Forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
$DomainList = $forest.domains
$DomainList | % {
  $DCs += $_.DomainControllers | select Name

$DCs | % { 

  $Name = $_.name
  $PingHost = Test-Connection -computername $Name -quiet

  echo "DC Name: $Name"
  if (!$Pinghost) { write-host "Return Ping: $Pinghost" -foreground Red } else { echo "Return Ping: $Pinghost" }

  try {
    $ErrorActionPreference = "Stop"; #Throw a terminating error for a non-terminating error (can't contact server)
    Get-WmiObject win32_logicaldisk -computername $Name | Where-Object { $_.DriveType -eq 3 } | select @{label="Drive";expression={$_.deviceid}}, @{label="Free Space (%)";expression={[Math]::Round(($_.FreeSpace/$_.Size)*100, 0)}} | colorize-row | fl
  catch { #write the error message to the console
    'Error: {0}' -f $_.Exception.Message
  finally { #reset the error action back to continue to keep running the script
    $ErrorActionPreference = "Continue"; #Reset the error action pref to default

$workfile = repadmin.exe /showrepl * /csv 
$results = ConvertFrom-Csv -InputObject $workfile | where {$_.'Number of Failures' -ge 1}

#Here you set the tolerance level for the report
$results = $results | where {$_.'Number of Failures' -gt 1 }

if ($results -ne $null ) {
    $results = $results | select "Source DSA", "Naming Context", "Destination DSA" ,"Number of Failures", "Last Failure Time", "Last Success Time", "Last Failure Status" | ConvertTo-Html
    } else {
    $results = "There were no Replication Errors"

$results | out-file repl.html


Use PowerShell to Add Permissions to AD Container Objects for Machine Accounts Without using the AD Module

I am taking on SCCM 2012 at work, so currently, I’m working on a PowerShell script that installs all the prerequisites before installing the actual product. The list of prereqs is about a mile long, but so far, I’m batting 1.000.

One of the prereqs is to add Full Control permissions on the System Management container in AD for the machine account SCCM is being installed on. This is probably a relatively trivial task while using the AD module. However, I want the script to be a seamless process for the installer. I don’t want to have to connect to a DC or using 3rd party modules. My goal is to have the installer start the script and walk away, returning to a fully prepared machine.