Thursday, April 27, 2017

SCCM Notify Users of Stale Workstations Script

This is a script that will check for members of the stale workstations collection and email the assigned user of each workstation, requesting that they connect their machine

# ------------------------------------------------------------------------------------------------------------------------------------------
# Script to gather members of the stale workstations collection and email the assigned user of each workstation
# Dan Dill, Jan 2017
# ------------------------------------------------------------------------------------------------------------------------------------------

# Import the modules that we need
Import-Module ActiveDirectory
cd "C:\Program Files (x86)\Microsoft Configuration Manager\AdminConsole\bin"
Import-Module .\ConfigurationManager.psd1
cd CAS:

# Variables here
$SiteServer = 'yoursccmserver'
$SiteCode = 'xxx'
$CollectionName = 'Your Stale Workstations Collection'
$testing = "Disabled" # Set to Disabled to Email Users
$testRecipient = "testuser@domain.com"
$fallbackuser = "na\helpdeskuser" # This is used if the computer doesn't have a user affinity
$fallbackemail = "helpdeskemail@domain.com" # This is used if the affinity user's email address is blank
$from = "Company IT "
$smtpServer="yourmailserver.domain.com"
$logFile = "C:\temp\yourlog.log" # ie. c:\mylog.csv
$logging = "Enabled" # Set to Disabled to Disable Logging
#

# Check Logging Settings
if (($logging) -eq "Enabled")
{
# Test Log File Path
    $logfilePath = (Test-Path $logFile)
    if (($logFilePath) -ne "True")
    {
        # Create CSV File and Headers
        New-Item $logfile -ItemType File
        Add-Content $logfile "Date Run On,StaleComputer,AffinityUser,AffinityEmail,EmailSentTo"
    }
}

#Get collection of stale computer accounts
$Collection = Get-WmiObject -ComputerName $SiteServer -Namespace  "ROOT\SMS\site_$SiteCode" -Class SMS_Collection | where {$_.Name -eq "$CollectionName"}
$SMSClients = Get-WmiObject -ComputerName $SiteServer -Namespace  "ROOT\SMS\site_$SiteCode" -Query "SELECT * FROM SMS_FullCollectionMembership WHERE CollectionID='$($Collection.CollectionID)' order by name" | select *

#Main part of script here.  Goes through each member of the collection, tracks down the email adderess of the user connected to that
#collection member and then emails that email address
foreach ($Clientname in $SMSClients.name){

 #Get SCCM affinity-ed username associated with the computer name, selecting the first result as for some reason some PCs return multiple users
 $ClientUserName = (Get-CMUserDeviceAffinity -DeviceName $Clientname | select -first 1).uniqueusername
 $clientaffinityuser = $ClientUserName
 #Check to see if there is no user affinity with the computer, if blank then sub in from fallbackuser
 if (!$ClientUserName){$ClientUserName = $fallbackuser}

 #Get the email address for the affinity user
 $useremailaddress = (get-aduser $ClientUserName.substring(3) -Properties mail).mail
 $clientaffinityemail = $useremailaddress
 if (!$useremailaddress){$useremailaddress = $fallbackemail}
 # If Testing Is Enabled - Email Administrator
 if (($testing) -eq "Enabled"){$useremailaddress = $testRecipient}

 #Build content of notification email
 $subject = "IT Notification about $clientname "
 $firstname = (get-aduser $ClientUserName.substring(3)).givenname
 $computer = $clientname
 $body = "
 Dear $firstname,
 

Your Company computer $computer has not been connected to the Company network in 90 days or more.

Please connect this computer to the internal network at a Company office or via a remote VPN connection at your earliest convenience. Periodic connections to the Company network are necessary so that your computer can receive critical updates and definitions. These updates keep your computer running reliably and keep the company secure from viruses and malware. PCs that are not kept up to date and periodically connected to the Company may be disabled by the IT department.

If you have received this notification in error or if you have any questions or concerns please contact your local IT support person or the Help desk.

Thanks for helping to keep the Company secure.

IT

" #send email out Send-Mailmessage -Encoding UTF8 -smtpServer $smtpServer -from $from -to $useremailaddress -subject $subject -body $body -bodyasHTML -priority High #log results to log file if (($logging) -eq "Enabled") { $date = get-date Add-Content $logfile "$date,$clientname,$clientaffinityuser,$clientaffinityemail,$useremailaddress" } } # End of script

SCCM Application Request Notification Script

This is a script that will check for application requests in SCCM and send an email notification to a manager or approver


#####################################################################
### E-Mail-Notification for Application-Request in ConfigMgr 2012 R2
### original by Andre Picker - www.clientmgmt.de
### modified by Dan Dill
#####################################################################

### E-Mail Settings #################################################

$SmtpServer = "mailserver.domain.com"
$SenderMail = "configmgr-noreply@yourdomain.com"
$TargetMail = "whotosendto@yourdomain.com"
$Subject = "SCCM Application Catalog Request"
$Message = "You have received a new Application Request from System Center Configuration Manager:`n"
$Footer = "To process the request go to: \Software Library\Overview\Application Management\Approval Requests.`n`nOnce action has been taken please notify the application requester. `n`n*** This is an automatically generated email. Please do not reply to this message. ***"

### Queryinterval ####################################################

$interval = $(Get-Date).AddDays(-7)

### Get SMS.Sitecode #################################################

$smsproviderloc = "select * from sms_providerlocation"
$sitecode = Get-WmiObject -Query $smsproviderloc -Namespace "root\sms" -ComputerName YourSCCMServer
$sitecode = $sitecode.sitecode

### Query ############################################################

Get-WmiObject -Namespace "root\SMS\Site_$sitecode" -ComputerName YourSCCMServer -Class SMS_UserApplicationRequest | where {$_.CurrentState -match "1" -and [Management.ManagementDateTimeConverter]::ToDateTime($_.LastModifiedDate) -gt $interval} | Foreach-Object {

$User = $_.User
$Application = $_.Application
$Comments = $_.Comments
$Date = [Management.ManagementDateTimeConverter]::ToDateTime($_.LastModifiedDate)

Send-MailMessage -From $SenderMail -Subject "$Subject from $User" -To $TargetMail -Body "$Message`nUser: $user`nApplication: $Application `nDate: $Date `nComments: $Comments `n`n$Footer" -SmtpServer $SmtpServer
}



Tuesday, April 18, 2017

Password Expiration Email Notification Powershell Script

This is a script that will check specific domains in an AD forest and send password notifications out to people before their password expires. The notification email is sent in the user's native language based off the AD attribute for that user. This is based off this script here but with added functionality.
#################################################################################################################
# 
# Original Source: https://gallery.technet.microsoft.com/Password-Expiry-Email-177c3e27#content
# 
# Script to Send Automated Email Reminders when Users Passwords are due to Expire.
#
# Requires: Windows PowerShell Module for Active Directory
#
# Modified by Dan Dill to support multiple domains through discovery and notifications in multiple languages based 
# on user country lookup.
#
# For country codes see: http://userpage.chemie.fu-berlin.de/diverse/doc/ISO_3166.html
#
# http://danstechnotes.blogspot.com
# 
##################################################################################################################
# Please Configure the following variables....
$smtpServer="yourmailserver"
$from = "IT <helpdesk-noreply@eample.com>"
$logging = "Enabled" # Set to Disabled to Disable Logging
$logFile = "C:\temp\pwdchgnotification.log" # ie. c:\mylog.csv
$testing = "Disabled" # Set to Disabled to Email Users
$testRecipient = "testrecipient@example.com"
$date = Get-Date -format yyy-MM-dd
$adforest = "adforest.example.biz"
$domainstoexclude = "excludeddomain.example.biz"
# You will also want to scroll down and configure the body of the email notification that goes out to people to match
# your password policy and desired verbiage.
#
##################################################################################################################
#Actions begin here


# Check Logging Settings
if (($logging) -eq "Enabled")
{
    # Test Log File Path
    $logfilePath = (Test-Path $logFile)
    if (($logFilePath) -ne "True")
    {
        # Create CSV File and Headers
        New-Item $logfile -ItemType File
        Add-Content $logfile "Date Run On(yyyy-MM-dd),Name,CountryCode,UserDomain,EmailAddress,DaystoExpire,ExpiresOn"
    }
} # End Logging Check

# Clear Variables
if ($dcs){clear-variable dcs, users}

# Import AD Module
Import-Module ActiveDirectory

# Discover all DCs in forest
$domains = (get-adforest $adforest).domains
$domains.remove($domainstoexclude)

foreach ($d in $domains)
{
    $dcs += (get-ADDomainController -Discover -Domain $d).hostname
}

# Get Users From AD who are Enabled, Passwords Expire and are Not Currently Expired
# This iterates through the list of DCs, as pwdLastSet is not in the GC by default so
# we can't simply query the GC for all our users
foreach($adserver in $dcs)
{
    $users += get-aduser -filter {(UserPrincipalName -like '*') -and (mail -like '*')} -server $adserver -properties Name, PasswordNeverExpires, PasswordExpired, PasswordLastSet, EmailAddress, countryCode, UserPrincipalName  |where {$_.Enabled -eq "True"} | where { $_.PasswordNeverExpires -eq $false } | where { $_.passwordexpired -eq $false }
}

$DefaultmaxPasswordAge = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge

# Process Each User for Password Expiry
foreach ($user in $users)
{
    $Name = $user.Name
    $country = $user.countrycode
    $emailaddress = $user.emailaddress
    $passwordSetDate = $user.PasswordLastSet
    $PasswordPol = (Get-AduserResultantPasswordPolicy $user)

    #get domain of user by reading and stripping UPN
    $userdomain = $user.UserPrincipalName.substring($user.UserPrincipalName.indexof("@") + 1)

    # Check for Fine Grained Password
    if (($PasswordPol) -ne $null)
    {
        $maxPasswordAge = ($PasswordPol).MaxPasswordAge
    }
    else
    {
        # No FGP set to Domain Default
        $maxPasswordAge = $DefaultmaxPasswordAge
    }

  
    $expireson = $passwordsetdate + $maxPasswordAge
    $today = (get-date)
    $daystoexpire = (New-TimeSpan -Start $today -End $Expireson).Days
        
    # Set Greeting based on Number of Days to Expiry.

    # Check Number of Days to Expiry
    $messageDays = $daystoexpire

    if (($messageDays) -ge "1")
    {
        switch -regex ($country) 
            { 
                '124|840|36|554' {$messageDays = "in " + "$daystoexpire" + " days"} 
                '76' {$messageDays = "em " + "$daystoexpire" + " dias"} 
                '156' {$messageDays = "$daystoexpire" + " 天后"}
                '392' {$messageDays = "あと" + "$daystoexpire" + "日で"} 
                '410' {$messageDays = "안에" + "$daystoexpire" + " 날짜"}
                default {$messageDays = "in " + "$daystoexpire" + " days"}
            }
    }
    else
    {
        switch -regex ($country) 
            { 
                '124|840|36|554' {$messageDays = "today"}
                '76' {$messageDays = "hoje"} 
                '156' {$messageDays = "今天"}
                '392' {$messageDays = "本日で"}
                '410' {$messageDays = "오늘"}
                default {$messageDays = "today"}
            }
    }

    # Email Subject Set Here
    switch -regex ($country) 
    { 
        '124|840|36|554' {$subject="Your password will expire $messageDays"}  
        '76' {$subject="Sua senha vai expirar $messageDays"} 
        '156' {$subject="提醒:您的密码将在$messageDays 过期"}
        '392' {$subject="$messageDays パスワード期限満了"}
        '410' {$subject="당신의 비밀번호가 만료되면 $messageDays"} 
        default {$subject="Your password will expire $messageDays"}
    }
    
    # Country Code Quick Reference
    # 124=Canada  840=US 36=Australia 554=New Zealand
    # 76=Brazil
    # 156=China
    # 392=Japan
    # 410=Korea
    # 710=South Africa
  
    # Email Body Set Here, Note You can use HTML, including Images.
    switch -regex ($country) 
    { 
        '124|124|840|124|36|124|554|710' {$body = "
                        Dear $name,
                        <p> Your Password for your account in the domain $userdomain will expire $messageDays.<br>
                        To change your password on a PC press CTRL+ALT+Delete and choose Change Password.<br>
                        If you connect in remotely or do not use a company provided device, you may need to use
                        alternate methods to change your network password.<br><br>
                        As a reminder, a valid password will meet these requirements:<br><br>
                        <ul><li>Not contain the user's account name or parts of the user's full name that exceed two consecutive characters</li>
                        <li>Be at least ten characters in length<br>
                        <li>Contain characters from three of the following four categories:<br>
                            <ul><li>English uppercase characters (A through Z)</li>
                            <li>English lowercase characters (a through z)</li>
                            <li>Base 10 digits (0 through 9)</li>
                            <li>Non-alphabetic characters (for example, !, $, #, %)</li></ul>
                        <li>Last  password change was more than 30 days ago</li>
                        <li>Different from the last 4 passwords</li></ul><br>
                        <p>Thanks for helping to keep the company secure.<br><br>
                        IT</P>"
                  }  
        '76' {$body = "
                        Caro $name,
                        <p> Sua senha do domínio $userdomain vai expirar em $messageDays.<br> 
                        <p>Obrigado por ajudar a manter segura.<br><br>
                        IT</P>"
                  } 
        '156' {$body = "
                        $name, 您好!
                        <p> 您的域账号密码将在$messageDays 过期。<br>
                        如需更改密码请在电脑上按下 CTRL+ALT+Delete 并选择&#8220;更改密码&#8221;.<br><br>
                        IT</P>"
                  }
        '392' {$body = "
                        $name 様,
                        <p> ドメイン $userdomain におけるあなたのアカウントのパスワードが、$messageDays 期限満了となります。 <br>
                        IT部門</P>"
                  }
        '410' {$body = "
                        $name,~에게
                        <p> 도메인 $userdomain에서 당신의 계정에 대한 비밀번호가 만료가되면 $messageDays 일 지나서 만료가 되면,<br>
                        IT </P>"
                  }
        default {$body = "
                        Dear $name,
                        <p> Your Password for your account in the domain $userdomain will expire $messageDays.<br>
                        To change your password on a PC press CTRL+ALT+Delete and choose Change Password.<br>
                        If you connect in remotely or do not use a company provided device, you may need to use
                        alternate methods to change your network password.<br><br>
                        As a reminder, a valid password will meet these requirements:<br><br>
                        <ul><li>Not contain the user's account name or parts of the user's full name that exceed two consecutive characters</li>
                        <li>Be at least ten characters in length<br>
                        <li>Contain characters from three of the following four categories:<br>
                            <ul><li>English uppercase characters (A through Z)</li>
                            <li>English lowercase characters (a through z)</li>
                            <li>Base 10 digits (0 through 9)</li>
                            <li>Non-alphabetic characters (for example, !, $, #, %)</li></ul>
                        <li>Last  password change was more than 30 days ago</li>
                        <li>Different from the last 4 passwords</li></ul><br>
                        <p>Thanks for helping to keep our company secure.<br><br>
                        IT</P>"
                  }
    }

   
    # If Testing Is Enabled - Email Administrator
    if (($testing) -eq "Enabled")
    {
        $emailaddress = $testRecipient
    } # End Testing

    # If a user has no email address listed
    if (($emailaddress) -eq $null)
    {
        $emailaddress = $testRecipient    
    }# End No Valid Email

    # Send Email Message
    # This is where you want to set the number of days away from expiration for the email notification to be sent to the user
    # In the example below we send an email on the day it is expiring 0, and also 1, 3, 10, and 21 days away from expiration.
    if ($daystoexpire -eq "0" -or $daystoexpire -eq "1" -or $daystoexpire -eq "3" -or $daystoexpire -eq "10" -or $daystoexpire -eq "21")
    {
         # If Logging is Enabled Log Details
        if (($logging) -eq "Enabled")
        {
            Add-Content $logfile "$date,$Name,$country,$userdomain,$emailaddress,$daystoExpire,$expireson" 
        }
        # Send Email Message
        # Encode as UTF8 for US/AUS/CA/NZL users
        if (($country -eq '124') -or ($country -eq '840') -or ($country -eq '36') -or ($country -eq '554') -or ($country -eq '0'))
        {
        Send-Mailmessage -Encoding UTF8 -smtpServer $smtpServer -from $from -to $emailaddress -subject $subject -body $body -bodyasHTML -priority High
        }
        else
        # Encode as unicode for all other country codes
        {
        Send-Mailmessage -Encoding Unicode -smtpServer $smtpServer -from $from -to $emailaddress -subject $subject -body $body -bodyasHTML -priority High  
        }
    } # End Send Message
    
} # End User Processing

# End

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
  }
 }