Thursday, April 4, 2019

Revoke expired certificates from VMware vCSA with Embedded PSC

I was receiving errors indicating I had expired certificates in my vCenter, even though I had used the certificate manager to go through a complete refresh of the certificates. All the VMware KB articles that pointed me to the vecs-cli were fruitless. The certificate would say it successfully deleted, but it wouldn't actually delete. The following are steps I followed with support to get the certificates removed. (Note...this is not an officially supported method of removal by VMware...so continue at your own risk and create a snapshot of the vCSA before you proceed).

The process is to export the certs to crt files in the /tmp directory. Next run a script that scans all crt files for expired certificates, and then revokes all certificates that are expired.

  1. Create gencerts.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
import re
import os
import subprocess

class SearchFunctions( object ):
    def __init__( self, rawdatas ):
        block_expr = re.findall(b"^-+BEGIN CERTIFICATE-+.*?-+END CERTIFICATE-+\s",rawdatas,re.DOTALL|re.MULTILINE)
        self.GetData = block_expr ###### get results
        print("-- Done with data parse.")
######  Main function
class dataParse( object ):
    def __init__( self, rawdatas ):
        count = 1

        print("\n-- Running data parse...")
        sa = SearchFunctions(rawdatas)

        print("-- Begin writing certs to files...")
        for i in sa.GetData:
            i = i.decode("utf-8")
            file_name = 'cert%s.crt' % count
            with open(file_name, 'w') as f:
                print("- Writing cert to %s" % file_name)
                f.write(i)
                count = count+1

def main():
    usage="use it right"
    print("-- Enumerating certs.  Counting...")
    p = subprocess.check_output(["/usr/lib/vmware-vmca/bin/certool","--enumcert","--filter=all"])
    dataParse(p)
if __name__ == "__main__":

    main()

  1. Run ./gencerts.py
  1. Create Find-expired.sh
#!/bin/bash
CERTFILE=$1

if openssl x509 -checkend 86400 -in $CERTFILE 2> /dev/null | grep -q "Certificate will not expire"
then
        echo "$CERTFILE is still valid.  Skipping..."
elif openssl x509 -checkend 86400 -in $CERTFILE 2> /dev/null | grep -q "Certificate will expire"
then
    echo -e "\nCertificate is expired!  Adding $CERTFILE to expiredcerts.txt...\n"
    echo "$CERTFILE" >> expiredcerts.txt
else
    echo -e "\nthere was a problem checking the cert.  ignoring $CERTFILE.\n"
fi

  1. Run "for i in $(ls cert*.crt); do ./find-expired.sh $i ; done"
  1. Run "for i in $(cat expiredcerts.txt); do /usr/lib/vmware-vmca/bin/certool --revokecert --cert /tmp/$i ;done"
  2. Validate the certificates are all revoked, then delete the snapshot you created.

Thursday, September 20, 2018

PowerShell script to reset service account password and restart services on multiple servers.

Need: You need to reset the password for a service account on one or more services on multiple servers at the same time, and restart the impacted services.

Prerequisite: Create a txt file with all the servers that are using a specific service account for one or more services.  Create a column header of "servers" and just paste all the servers names below.You can compile this file from my earlier blogpost here.

Script:

$newpass = "ReallyLongPasswordYouWouldHateTyping"
Import-csv C:\data\computers.txt|foreach-object {
$server = $_.servers
$services = get-wmiobject win32_service -ComputerName $server |?{$_.Startname -like "*svcaccountname*"}
foreach($service in $services)
{$service.change($null,$null,$null,$null,$null,$null,$null,$newpass)
get-service $service.name -ComputerName $server|stop-service
start-sleep -s 30
get-service $service.name -ComputerName $server|start-service
}}

Tuesday, August 7, 2018

PowerShell script to find all services using domain credentials

Whether it's changing a service account password, or looking for admins running service accounts under their own credentials, this script will come in handy. If you put a list of computer names or IP addresses in a servers.txt file, you can grab all services that have an account configured with your domain name or upn.

Import-csv C:\temp\servers.txt|foreach-object{
get-wmiobject win32_service -ComputerName $_.Server |?{$_.Startname -like "*Domain*" -or $_.Startname -like "*UPNSuffix*"}|select PSComputerName,Name,Started,State,StartName,Description|export-csv C:\temp\services.csv -append -notypeinformation
}
Results:

Thursday, May 3, 2018

User Home Drive Report


I was tasked with creating a report on our user home drives of information on every file, such as name, size, modified date, file extension, etc. They also wanted to include information on the user, including things like their name, location, department, and title. Since the home drives are created with the username, it made it pretty easy.

Get-ChildItem "\\fileserver\users$" |Where-Object {$_.psiscontainer -eq $true}|Select-Object -First 10|ForEach-Object{
 Get-ChildItem $_.FullName -Recurse -ErrorAction SilentlyContinue|Where-Object {$_.psiscontainer -eq $false}|Foreach-Object{
  $EID = $_.FullName
  $EID = $EID.Trim("\\\\fileserver\\users$\\")
  $EID = $EID.Substring(0,6)
  $User = (get-aduser $EID -Properties GivenName,Surname,Title,StreetAddress,Department,HomeDirectory)
  $UName = $User.GivenName + " " + $User.Surname
  $Server=$_.FullName.Trim("\\\\")
  $Server=$Server.Split('\\')[0]
 
$props = @{
    EmployeeID = $EID
    UserName = $UName
    UserTitle = $User.Title
    UserLocation = ($User.StreetAddress|Select-Object -First 1)
    UserDepartment = $User.Department
    UserHomeDirectory = $User.HomeDirectory
    File = $_.FullName
    FileServer = $Server
    Extension = $_.Extension
    CreationTime = $_.CreationTime
    LastWriteTime = $_.LastWriteTime
    Name = $_.Name
    SizeInKB = [math]::Round($_.Length/1024,2)
}
  $Export = new-object psobject -Property $props 
  $Export|export-csv -append C:\temp\First10.csv -NoTypeInformation
  $User = $null
}
}

Notes: This was made with the assumption that the employeeID is a fixed length of 6 characters, so you may need to adjust for your environment. Also, if you have a large number of users or files, you will need to break the data into more manageable sizes. I did this using the Select-Object command.

Thursday, March 1, 2018

Free up disk space on 2008/R2 Servers

It's no secret that 2008/R2 servers do a horrible job with the WinSxS folder growing ridiculously out of control. Microsoft's stance is, "Deal with it." They have options for newer operating systems, but 2008/R2 is not so blessed. If you have a physical server, or other reasons the disk is unable to be easily expanded, you can be desperately low on free disk space, while WinSxS consumes over 20GB. Here's what I've found that helps, with no reboots required:

First, try to clean up the files left over from a Service Pack installation with the following command:
DISM.exe /online /Cleanup-Image /SPSuperseded

That can sometimes buy you a few GB, but if you need more, consider compressing the WinSxS folder, which can free up many GBs, as you can see in this example. Since compression doesn't delete anything, and these files are seldom referenced, it should result in no negative impact upon the server.



Step 1 - Stop services and backup ACL
sc stop msiserver
sc stop TrustedInstaller
sc config msiserver start= disabled
sc config TrustedInstaller start= disabled
icacls "%WINDIR%\WinSxS" /save "%WINDIR%\WinSxS.acl" /t

Step 2 - Take ownership
takeown /f "%WINDIR%\WinSxS" /r

Step 3 - Grant permissions
icacls "%WINDIR%\WinSxS" /grant "Domain\Username":(F) /t
*This would be the username you have used to login to the server, or you can always grant it to a group of which your account is a member, like Domain Admins.

Step 4 - Compress files
compact /s:"%WINDIR%\WinSxS" /c /a /i *

Step 5 - Restore permissions
icacls "%WINDIR%\WinSxS" /setowner "NT SERVICE\TrustedInstaller" /t
icacls "%WINDIR%" /restore "%WINDIR%\WinSxS.acl"

Step 6 - Delete ACL backup and start services
del "%WINDIR%\WinSxS.acl"
sc config msiserver start= demand
sc config TrustedInstaller start= demand

Monday, April 18, 2016

Email DHCP Scope Statistics in an HTML table



I was asked to send an email daily of our DHCP Scope Statistics to our VDI team, so they can plan properly and monitor usage on some scopes where IP addresses are tight. I know...it sounds incredibly exciting and you're all wondering how I sleep at night when I get to do such cool stuff! Anyway, I came up with this script to email the DHCP Scope Statistics on a daily basis. We have monitoring enabled that will alert us if the scopes are running out of IP addresses, but in an effort to be more proactive, they wanted a simple email. Since everyone and their dog emails out Excel attachments every day, I wanted to mix things up a bit and just send the data in HTML, since they were only using this for reference and not actually doing anything with the data.

Script Requirements:
- Powershell v2
- DHCP Servers 2008-2012R2
- DHCP PowerShell Module

Usage: Modify the Send-MailMessage line with appropriate sender, recipient, and SMTP information. There are no other changes that are required, as it will detect DHCP Servers in your domain and report from all Active DHCP Scopes. Simply run the Get-DHCPScopeStats.ps1 script and wait for your email.

Features:
  • Exports DHCP Scope Statistics from all Active DHCP Scopes in the domain
  • Displays Scope Name, Network, DHCP Server, Free IPs, IPs in Use, Start, and End of DHCP Scope.
  • Sends email in HTML format with embedded table for an easy read without opening an attachment.
Sample from Email:

PowerShell
Import-Module DhcpServer 
 
$a = "" 
$a = $a + "BODY{background-color:White;font-family: Arial; font-size: 10pt;}" 
$a = $a + "TABLE{border-width: 1px;border-style: solid;border-color: black;border-collapse: collapse;}" 
$a = $a + "TH{border-width: 1px;padding: 5px;border-style: solid;border-color: black;background-color:silver}" 
$a = $a + "TD{border-width: 1px;padding: 5px;border-style: solid;border-color: black;background-color:WhiteSmoke}" 
$a = $a + "" 
 
$DHCPStats = @() 
$DHCPStatsString = @() 
 
show-dhcpservers|foreach-object { 
$DHCPSrvr = $_.Server 
Get-DhcpServerv4Scope -ComputerName $_.Server|where {$_.State -eq 'Active'}|ForEach-Object { 
$ScopeName = $_.Name 
$ScopeID = $_.ScopeID 
$SM = $_.SubnetMask 
$Start = $_.StartRange 
$End = $_.EndRange 
$Lease = $_.LeaseDuration 
$State = $_.State 
$IPFree = (Get-DhcpServerv4ScopeStatistics -ComputerName $DHCPSrvr -ScopeID $ScopeID).Free 
$IPInuse = (Get-DhcpServerv4ScopeStatistics -ComputerName $DHCPSrvr -ScopeID $ScopeID).Inuse 
$DHCPStats = New-Object -TypeName PSObject 
$DHCPStats | Add-Member -MemberType NoteProperty -Name ScopeName -Value $ScopeName 
$DHCPStats | Add-Member -MemberType NoteProperty -Name ScopeNetwork -Value $ScopeID 
$DHCPStats | Add-Member -MemberType NoteProperty -Name FreeIPs -Value $IPFree 
$DHCPStats | Add-Member -MemberType NoteProperty -Name DHCPServer -Value $DHCPSrvr 
$DHCPStats | Add-Member -MemberType NoteProperty -Name IPsInUse -Value $IPInuse 
$DHCPStats | Add-Member -MemberType NoteProperty -Name Start -Value $Start 
$DHCPStats | Add-Member -MemberType NoteProperty -Name End -Value $End 
$DHCPStatsString +$DHCPStats 
} 
} 
$DHCPStatsBody = $DHCPStatsString|Select ScopeName, ScopeNetwork, DHCPServer, FreeIPs, IPsInUse, Start, End|Sort-object FreeIPs|ConvertTo-HTML -Head $a -Body "<H2>DHCP Server Statistics</H2>" 
$body = "<font face='arial'> " 
$body +"`n" 
$body +$DHCPStatsBody 
$body +"`n" 
 
Send-MailMessage -From "SourceEmail@contoso.com" -To "Recipient@contoso.com" -Subject "DHCP Scope Statistics" -Body "$body" -BodyAsHtml -SmtpServer "smtp.contoso.com"

Sunday, November 22, 2015

Don't forget to disable short filenames (8.3) on servers with folders containing many files.

Microsoft disabled short filenaming (8.3) by default starting with Windows 8 / Server 2012. However, this week I ran into a situation where we were unable to write files to a folder that already contained 2.2 million files on a 2008 server. It is easy to argue that a software design that dumps millions of files into a single folder is flawed, sometimes we find ourselves in situations that we cannot fix with design at the time. I attempted to defrag the folder and MFT with contig.exe, without success. A chkdsk didn't help, so I began moving the files to a new folder. This went very fast, but once I got near 1 million files, it slowed to around 6,000 files per hour. I tried robocopy, move, PowerShell's move-item, and nothing was making it any faster.

I found some references to disabling 8.3 short file names (https://support.microsoft.com/en-us/kb/121007), and gave it a shot. This was a 2008 server, and not 2008 R2, so I couldn't take advantage of the fsutil command, even though it references that Operating System in the article. I used this article (https://technet.microsoft.com/en-us/library/cc778996.aspx) to manually set the registry entry for NtfsDisable8dot3NameCreation to 3. After a reboot, the move went from 6,000 files per hour, to 1 million files in 30 minutes!

So if you do not have a need for short filenames on your servers where you have a large number of files (more than 30,000) in a single folder, I highly recommend revisiting this old subject and making a switch. If you can use 2008 R2's fsutil to execute the strip command and remove the short filenames, even better. If you are on a 2008 or prior server, then moving the files to a different directory, should be sufficient to remove the short filenames, then rename that directory to match the old name.