Tuesday, April 18, 2017

VMware Snapshot Auto Delete Powershell Script

This script will look through vcenter for snapshots that have a specific description. If description matches criteria, then snapshot will be deleted and notification sent based on contents of snapshot description. Requires VMware snapin/module


# Script to auto delete vmware snapshots based on text in snap description
#
# Dan Dill, 2017

# variables here
$date = get-date -format MM/dd/yyyy
$dateregex = "(0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])[- /.](19|20)[0-9]{2}"
$emailregex = '\w+\.\w+@\w+\.\w+'
$vcenterserver = 'vcenterserver.domain'
$emaildomain = '*@domain.com*'
$mailserver = 'mailserver.domain'
$from = "Vmware Robot "

# Load PowerCli
# Load VMware Snapin or Module (if not already loaded)  
if (!(Get-Module -Name VMware.VimAutomation.Core) -and (Get-Module -ListAvailable -Name VMware.VimAutomation.Core)) {  
    Write-Output "loading the VMware COre Module..."  
    if (!(Import-Module -Name VMware.VimAutomation.Core -ErrorAction SilentlyContinue)) {  
        # Error out if loading fails  
        Write-Error "`nERROR: Cannot load the VMware Module. Is the PowerCLI installed?"  
  }
 }

#connect to vcenter and grab snaps with description that contains 'AutoDelete' or 'Auto Delete'
connect-viserver $vcenterserver
$snaps = get-vm | get-snapshot | where {$_.description -like '*AutoDelete*' -or $_.description -like '*Auto Delete*'}

#main loop of script, executes for each snapshot found
foreach ($snap in $snaps){
 # grab date in snap in format mm/dd/yyyy
 $snapdate = [datetime](select-string -inputobject $snap.description -pattern $dateregex | Select -First 1).matches.value
 $snaplist = $snap | select name,description,created,VM | fl | out-string
 # if the snapshot description date matches today then act upon it
 if ($snapdate -eq $date){
  # if the description has an email domain match then send out a notification email
  if ($snap.description -like $emaildomain){
   $emails = (Select-String -InputObject $snap.description -Pattern $emailregex).matches
    foreach ($email in $emails){
    send-mailmessage -from $from -to $email -subject "Snapshot Deletion" -body "Hello, the system is deleting the following snapshot $snaplist " -smtpServer $mailserver
    }
   }
   # delete the snapshot
   $snap | Remove-Snapshot -confirm:$false
   clear-variable snaplist
   # wait 60 seconds just to be nice to the storage system
   start-sleep -s 60
  }
 }

Thursday, February 23, 2017

SCCM Copy Random members to a collection powershell script

This script will take a given source SCCM collection and randomly grab a percentage of that collection and add it to a destination collection


cd "C:\Program Files (x86)\Microsoft Configuration Manager\AdminConsole\bin"
Import-Module .\ConfigurationManager.psd1
cd CAS:

#$SrcCollectionName = 'source collection name'
#$DstCollectionName = 'destination collection name'


$SiteServer = 'siteservername'
$SiteCode = 'threelettersitecode'
$PercentToGet = 23
$UpdateCollectionMembership = $true

#uncomment this if you want/need to prompt for credentials
#$cred = Get-credential

[System.Collections.ArrayList]$DstItemList = @()
[System.Collections.ArrayList]$SrcItemList = @()

write-output "Going to clear out direct members of $DstCollectionName and then randomly collect $PercentToGet percent of the members of $SrcCollectionName and add them to $DstCollectionName "

#Gather collection ID and list of Items in src and dst collections
$SrcCollectionID = Get-CMDeviceCollection -Name $SrcCollectionName | Select CollectionID
$DstCollectionID = Get-CMDeviceCollection -Name $DstCollectionName | Select CollectionID
$SrcItemList = @(Get-CMDevice -CollectionId $SrcCollectionID.CollectionID | Select -Property Name, ResourceID)
$DstItemList = @(Get-CMDevice -CollectionId $DstCollectionID.CollectionID | Select -Property Name, ResourceID)

#clear out existing destination collection members
ForEach ($DstItem in $DstItemList)
 {
    $name = $DstItem.name
    $ID = $DstItem.ResourceID
    write-output "Removing $name with ID $ID from collection $DstCollectionName"
    Remove-CMDeviceCollectionDirectMembershipRule -CollectionName $DstCollectionName -ResourceId $ID -force
    }

#run update membership to update destination collection 
write-output "Triggering update membership for collection $DstCollectionName "
    $ID = $DstCollectionID.CollectionID
    Invoke-WmiMethod -Path "ROOT\SMS\Site_$($SiteCode):SMS_Collection.CollectionId='$ID'" -Name RequestRefresh -ComputerName $SiteServer 

#wait 4 minutes for the collection to update
write-output "Waiting 4 minutes for the update membership for collection $DstCollectionName "
start-sleep -s 240
 
#run update membership to update source collection as source collection may exclude previous destination collection
#this may not be necessary?
write-output "Triggering update membership for collection $SrcCollectionName "
    $ID = $SrcCollectionID.CollectionID
    Invoke-WmiMethod -Path "ROOT\SMS\Site_$($SiteCode):SMS_Collection.CollectionId='$ID'" -Name RequestRefresh -ComputerName $SiteServer 

#wait 4 minutes for the collection to update
write-output "Waiting 4 minutes for the update membership for collection $SrcCollectionName "
start-sleep -s 240

#Refresh contents for source collection arraylist
$SrcItemList = @(Get-CMDevice -CollectionId $SrcCollectionID.CollectionID | Select -Property Name, ResourceID)
 
#clear list of destination items to be used for input
Clear-variable DstItemList
[System.Collections.ArrayList]$DstItemList = @()

#Calc number of destination-bound items that we want to end up with
$DstNumberOfItems = ($SrcItemList).count * ($PercentToGet / 100)
$DstNumberOfItems = [math]::truncate($DstNumberOfItems)

write-output "Going to search for and add $PercentToGet Percent - $DstNumberOfItems items - to collection $DstCollectionName "

#go through source list and pick random items till we have enough
While ($NumberOfItems -ne $DstNumberOfItems)
 {
 $PickedItem = ($SrcItemList | Get-Random)
    $DstItemList += $PickedItem
 $SrcItemList.remove($PickedItem)
    $NumberOfItems = $DstItemList.count
 }

#add items to destination collection list
ForEach ($DstItem in $DstItemList)
 {
    $name = $DstItem.name
    $ID = $DstItem.ResourceID
    write-output "Adding $name with ID $ID to collection $DstCollectionName "
 Add-CMDeviceCollectionDirectMembershipRule -CollectionName $DstCollectionName -ResourceId $ID
 }

# trigger update collection membership if enabled in script
# this portion of the script is from:
# https://www.petervanderwoude.nl/post/update-collection-membership-in-configmgr-2012-via-powershell/

If ($UpdateCollectionMembership)
    {
 write-output "Triggering update membership for collection $DstCollectionName "
    $ID = $DstCollectionID.CollectionID
    Invoke-WmiMethod -Path "ROOT\SMS\Site_$($SiteCode):SMS_Collection.CollectionId='$ID'" -Name RequestRefresh -ComputerName $SiteServer
 
 #wait 4 minutes for the collection to update
 write-output "Waiting 4 minutes for the update membership for collection $DstCollectionName "
 start-sleep -s 240
 
    write-output "Triggering update membership for collection $SrcCollectionName "
    $ID = $SrcCollectionID.CollectionID
    Invoke-WmiMethod -Path "ROOT\SMS\Site_$($SiteCode):SMS_Collection.CollectionId='$ID'" -Name RequestRefresh -ComputerName $SiteServer


    }

Wednesday, February 1, 2017

Expired Files Deletion Script

This is a script that checks through a list of folders based on a standard set of folders at multiple sites and purges old files. Nothing too fancy here.

# Script to look at folders and delete old items

$logfile = "c:\folder\logfilename.txt"
$date = get-date
$allfilestodelete

# Set variables for the timeframes used to determine stale files
$1wlimit = ($date).AddDays(-8)
$1mlimit = ($date).AddDays(-32)
$6mlimit = ($date).AddDays(-187)
$1ylimit = ($date).AddDays(-366)

# Test Log File Path, create a log file if it doesn't exist
    $logfilePath = (Test-Path $logFile)
    if (($logFilePath) -ne "True")
    {
        # Create File
        New-Item $logfile -ItemType File
        Add-Content $logfile "Log file created $date "
    }

Add-Content $logfile "AutoDelete script starting to run on: $(get-date) "

# This is the prefixes that we will use to mate with the suffixes to set all the folders that we are looking at
$siteuncprefixes = "\\server1\share\","\\server2\share\","\\server3\share\"

# These are the suffixes, so we will end up with \\server1\share\foldername\1weekfolder, 
# \\server1\share\foldername\1monthfolder and so on...
$1wuncsuffix = "foldername\1weekfolder"
$1muncsuffix = "foldername\1monthfolder"
$6muncsuffix = "foldername\6monthsfolder"
$1yuncsuffix = "foldername\1yearfolder"

# Main loop to look at each site's folders and check for stale files
foreach ($site in $siteuncprefixes){

        Add-Content $logfile "Scanning $site for expired files at $(get-date) "

  $currentpath = $site + $1wuncsuffix
        #Add-Content $logfile "Scanning $currentpath for 1 week expired files at $(get-date) "
  $1wfilestodelete = Get-ChildItem -Path $currentpath -Recurse -Force | Where-Object { !$_.PSIsContainer -and $_.lastwriteTime -lt $1wlimit -and $_.creationtime -lt $1wlimit }
  
  $currentpath = $site + $1muncsuffix
        #Add-Content $logfile "Scanning $currentpath for 1 month expired files at $(get-date) "
  $1mfilestodelete = Get-ChildItem -Path $currentpath -Recurse -Force | Where-Object { !$_.PSIsContainer -and $_.lastwriteTime -lt $1mlimit -and $_.creationtime -lt $1wlimit }

  $currentpath = $site + $6muncsuffix
        #Add-Content $logfile "Scanning $currentpath for 6 month expired files at $(get-date) "
  $1mfilestodelete = Get-ChildItem -Path $currentpath -Recurse -Force | Where-Object { !$_.PSIsContainer -and $_.lastwriteTime -lt $6mlimit -and $_.creationtime -lt $1wlimit }
  
  $currentpath = $site + $1yuncsuffix
        #Add-Content $logfile "Scanning $currentpath for 1 year expired files at $(get-date) "
  $1yfilestodelete = Get-ChildItem -Path $currentpath -Recurse -Force | Where-Object { !$_.PSIsContainer -and $_.lastwriteTime -lt $1ylimit -and $_.creationtime -lt $1wlimit }

  $allfilestodelete = $allfilestodelete + $1wfilestodelete + $1mfilestodelete + $6mfilestodelete + $1yfilestodelete

}

# Count the total number of files and write to the log file
$count = $allfilestodelete.fullname.count
Add-Content $logfile "Found $count expired files to delete at all sites: "

# Write to the log all items to be deleted
$allfilestodelete | select-object -property fullname, lastwritetime | Ft -autosize | out-string -width 4096 | add-content $logfile

# Delete expired files
$allfilestodelete.fullname | Remove-Item -Force

# Write to the log file that it's done
Add-Content $logfile "AutoDelete script finished runing on: $(get-date) "

Tuesday, June 30, 2015

Check WSUS Proxy Setting for All Servers in a Domain

Here's a handy couple of powershell lines to check the proxy address (within the WSUS config) for all the servers in your domain with WSUS in the name.

$wsusservers = (get-adcomputer -filter {name -like "*WSUS*"} ).name

invoke-command $wsusservers -scriptblock {$config=(get-wsusserver).getconfiguration();write-host $env:computername "- " -nonewline ;write-host $config.proxyname "- port:" -nonewline ;$config.proxyserverport}

Thursday, April 19, 2012

Netapp DataMotion move is slow

I was scratching my head recently about why moving Netapp volumes on my filer was going so slowly and just ran across the reason.

Here is the Netapp TR on DataMotion which explains in further detail what DataMotion is and does: NetApp DataMotion for Volumes

The reason why it was going slower than it should was the fact that the "vol move" command is using snapmirror to actually move the data. In our case I had enabled options.replication.throttle so as to make sure to not beat up our WAN with snapmirror traffic. This throttles all snapmirror traffic on a given filer so my local volume move was limited to the limit I had set for moving data across the WAN which was far from ideal. So if you're hitting the throttle setting either bump up that limit or temporarily turn throttling off (options.throttle.enable off) if you'd like to move that volume faster.

Monday, March 5, 2012

Email is not always sent in the clear!

Heard this information in an article today from Marketplace Tech report which is here which contains information and content from a computerworld article here.

"email is not even transmitted encrypted, it's transmitted in the clear" - David Jefferson, a computer scientist at Lawrence Livermore National Laboratories and chairman of the election watchdog group Verified Voting.

This is completely false for some email. Period.

Misinformation or misleading things in the news bother me so this I felt compelled to write about. Email is not necessarily sent in the clear. Yes it can be however that's not always the case. I suppose some email may be transmitted in the clear by older systems and people that have configured their systems to act that way. Same as if you wanted to you could mail someone cash through the postal service, yes you could do that if you wanted to, but the statement of "everyone sends cash through the postal service" would be false.

So the question of course is how much email is transmitted this way? Well, Microsoft Exchange email systems had a 65% market share as of 2009 (1) so it's safe to say at least a significant portion of email traffic flows through Microsoft Exchange Email servers. The exact percentage of "how much email is sent in the clear versus encrypted" would be a bit challenging for me to quantify and is beyond my means so is not something I can answer.

However it is important to note that modern email systems have the ability (if not the default) to transmit via an encrypted connection. This is done in some cases via TLS or can be done via "opportunistic TLS" as Microsoft has implemented. You could even (in situations requiring higher security) require all mail sent to you to be encrypted.

Microsoft Exchange 2007 (2) and 2010 (3) have this feature enabled by default and as such if the other end supports it, they will encrypt their email sent to said systems.

It looks like sendmail (popular linux SMTP software) also by default will try to establish a TLS session when sending email. (4)

Yes this method of sending email in an encrypted manner is not a perfectly secure system, nor are most (if any) systems perfectly secure. However to state that email is sent "in the clear" is only partially true at best. For a hypothetical organization dealing with voting, they could easily require encryption of all email sent to them which would mean no hypothetical votes would be emails sent "in the clear"


1 - http://www.microsoft.com/presspass/features/2009/jan09/01-16qascult.mspx

2 - http://technet.microsoft.com/en-us/library/bb430753(v=exchg.80).aspx

3 - http://technet.microsoft.com/en-us/library/bb430753.aspx

4 - http://www.sendmail.org/m4/starttls.html#disable_starttls

Tuesday, August 2, 2011

Powershell Script to Archive IIS Log Files

Here's a script that I put together to deal with windows server log files (Mainly IIS) as previously it was a manual process for me and something I got sick of. I found scripting pieces around that were close to what I wanted but didn't fine something exactly so mashed this script together.

The script basically takes a list of servers you give it, checks each server to determine if it's 2003 or 2008, (as default IIS directories changed between 03 and 08) and then will look in the default IIS log files location for files. Anything older than the age specified it will move into a sub-folder named the year.

One shortcoming is that the script assumes there is already a folder created in your log files directory with the year. I did this as that way I could simply enable compression on those "archive" folders and then not have to deal with that in my script as it seemed to be a pain to try to enable compression using powershell. So if I wanted to put more effort into it there is certainly room for improvement.

Here's the script:




# Script to cleanup IIS files on various given servers

#define parameters
$iispath03 = "\C$\WINDOWS\system32\LogFiles\"
$iispath08 = "\C$\inetpub\logs\LogFiles\"
$OS = "default"

#set archive period after which to move logs to compressed folder
$Now = Get-Date
$Days = “8”
$LastWrite = $Now.AddDays(-$days)

#define list of IIS servers to cleanup logs on
$IISServers = @("server1","server2","server3","server4","etc","etc","etc","etc")


#Define Function to check if server 03 or 08
Function GetServerOS
{param ($strServerName)
$strCategory = "computer"
$strfilter = "(&(objectCategory=Computer)(Name=$strServerName))"

$objDomain = New-Object System.DirectoryServices.DirectoryEntry
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = $objDomain
$objSearcher.Filter = $strfilter
$colProplist = “operatingsystem”

foreach ($i in $colPropList){$objSearcher.PropertiesToLoad.Add($i)}

$colResults = $objSearcher.FindAll()

foreach ($objResult in $colResults)
{$objComputer = $objResult.Properties
$objComputer.operatingsystem
}

}

#Gather list of IIS log file directories
foreach ($server in $IISServers)
{

#Check OS of server in question
$FullOS = GetServerOS $server
if ($FullOS[1].Contains("2003")){
$OS = "2003"
$IISDir = "\\" + $server + $iispath03
}
elseif($FullOS[1].Contains("2008")){
$OS = "2008"
$IISDir = "\\" + $server + $iispath08
}
else{
$OS = "Error"
$IISDir = "Error"
}

$IISLogDirs = dir $IISDir W3* | where {$_.psIsContainer -eq $true} | select fullname
if($IISLogDirs)
{

#Cycle through each of the discovered directories
foreach ($dir in $IISLogDirs)
{
#set current directory (should be compressed) to archive files to
$archivedir = $dir.fullname + "\" + $Now.year + "\"

#check if the current year directory exists, if not create it
if (!(Test-Path -path $archivedir))
{
New-Item $archivedir -type directory
}

#Get list of log files to cleanup
$logfiles = get-childitem $dir.fullname *.log | Where {$_.LastWriteTime -le “$LastWrite”} | select fullname
if($logfiles)
{
foreach ($file in $logfiles)
{
copy-item $file.fullname $archivedir
remove-item $file.fullname
}

}

}

}

}