DansPSFuncs.psm1

<#
$path = "D:\_MyProfile\Documents\WindowsPowerShell\Modules\DansPSFuncs\DansPSFuncs.psd1"
# $guid = [guid]::NewGuid().guid ## 43b2e1ad-93fc-4612-bfdf-625eba3af91a
 
$paramHash = @{
 Path = $path
 # AliasesToExport = ""
 Author = "Dan Murray"
 #RootModule = "DansPSFuncs.psm1"
 CompanyName = "Dan Murray"
 ModuleVersion = "1.0"
 Guid = $guid
 PowerShellVersion = "5.0"
 Description = "Dan Murrays functions"
 ReleaseNotes = "These are my custom functions"
 # FormatsToProcess = ""
 # FunctionsToExport = ""
 # VariablesToExport = ""
 # CmdletsToExport = ""
}
New-ModuleManifest @paramHash -passthru
#>

<# Comment_based_Help
.NOTES
 Author: DMurray
 
.SYNOPSIS
 Dans PowerShell Functions
 
#>
 #Comment_based_Help
Function __Process-HRBFiles {
<#
.SYNOPSIS
   Short description
.DESCRIPTION
   Long description
.EXAMPLE
   Example of how to use this cmdlet
.EXAMPLE
   Another example of how to use this cmdlet
.INPUTS
   Inputs to this cmdlet (if any)
.OUTPUTS
   Output from this cmdlet (if any)
.NOTES
   General notes
.COMPONENT
   The component this cmdlet belongs to
.ROLE
   The role this cmdlet belongs to
.FUNCTIONALITY
   The functionality that best describes this cmdlet
#>

    [CmdletBinding(
        SupportsShouldProcess=$true, 
        PositionalBinding=$false
        )]
    Param (
        <# Param1 help description
        [Parameter(Mandatory=$true,
                   ValueFromPipeline=$true,
                   ValueFromPipelineByPropertyName=$true,
                   ValueFromRemainingArguments=$false,
                   Position=0,
                   ParameterSetName='Parameter Set 1')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [ValidateCount(0,5)]
        [ValidateSet("sun", "moon", "earth")]
        [Alias("p1")]
        $Param1,
 
        # Param2 help description
        [Parameter(ParameterSetName='Parameter Set 1')]
        [AllowNull()]
        [AllowEmptyCollection()]
        [AllowEmptyString()]
        [ValidateScript({$true})]
        [ValidateRange(0,5)]
        [int]
        $Param2,
 
        # Param3 help description
        [Parameter(ParameterSetName='Another Parameter Set')]
        [ValidatePattern("[a-z]*")]
        [ValidateLength(0,15)]
        [String]
        $Param3
        #>

        #HRB Data Folder
        [Parameter(
            ValueFromPipeline=$true,
            ValueFromPipelineByPropertyName=$true
            )]
        $hrbDataDir='\\vab-vfp-01\hrb_updates$',
        
        #HRB Data FileSpec
        [Parameter(
            ValueFromPipeline=$true,
            ValueFromPipelineByPropertyName=$true
            )]
        $hrbDataFile = 'EMP LIST FOR ACTIVE DIRECTORY'
    )

    Begin {
        #region BaseVariables
        #region MailSplats
            $smtpSplat = @{}
            $smtpSplat.from   = 'McKean Help Desk <helpdesk@mckean-defense.com>'
            $smtpSplat.to     = @('McKean Help Desk <helpdesk@mckean-defense.com>',
                            'John Scipione <JScipione@mckean-defense.com>',
                            'Dan Murray <dmurray@mckean-defense.com>')
            $smtpSplat.cc     = @()
            $smtpSplat.SmtpServer = 'smtp.mckean.local'
            $smtpSplat.body   = @()

            $RunMsgSplat = $smtpSplat
            $RunMsgSplat.Subject = 
                "Started Process: $((Get-PSCallStack)[0].Command) at $((get-date).ToString("HH:mm MMM dd, yyyy"))"
            $RunMsgSplat.body    = @()
        
            #LEGACY
            $mail         = $smtpSplat
            $mail.from   = 'McKean Help Desk <helpdesk@mckean-defense.com>'
            $Mail.to     = @('McKean Help Desk <helpdesk@mckean-defense.com>',
                            'John Scipione <JScipione@mckean-defense.com>',
                            'Dan Murray <dmurray@mckean-defense.com>')
            $Mail.cc     = @('Dan Murray <dmurray@mckean-defense.com>')
            $mail.SmtpServer = 'smtp.mckean.local'
            $mail.body   = 
                "See attached log file...",
                "#assign dmurray",
                "#close",
                "#mute" ,
                "" | Out-String
        
        #endregion MailSplats
        $scriptName=(Get-PSCallStack)[0].Command
        $RunDate=(get-date).tostring("yyyyMMMdd-HHmm").ToUpper()
        
  
        $TheSrchBase = "OU=mckean",$((Get-ADDomain).distinguishedName) -join ','
        $TermedBase  = "OU=TERMED,OU=Special Users",$((Get-ADDomain).distinguishedName) -join ','
        $SPGroupOU   = 'OU=Sharepoint Groups,OU=Groups',$TheSrchBase -join ','
        $ActvUsrOU   = 'OU=Users',$TheSrchBase -join ','
        $Summary = @()
        $TestEmplIDs = @(999,9999)

        $tab ="`t"
        $cr  ="`r`n"
        #region Counts
        $Counts      =
            @{}
        $Counts.i    =
            0
        $Counts.NewUsers =
            0
        $Counts.DisUsers =
            0
        $Counts.NoAdds   =
            0
        $Counts.Skipped  =
            0
        $Counts.NotDisabled = 
            0
        #endregion Counts
        #region ADP_2017_codes
        $ADP_2017_codes=@{}
        $ADP_2017_codes.add('1','')
        $ADP_2017_codes.add('101','EOM')
        $ADP_2017_codes.add('10103','CABRILLO GROUP')
        $ADP_2017_codes.add('010300','CAB - GRP MGMT')
        $ADP_2017_codes.add('010301','CAB - OPERATION')
        $ADP_2017_codes.add('10104','MCKEAN TECHNICAL SERVICES GROUP')
        $ADP_2017_codes.add('010400','MTS - GRP MGMT')
        $ADP_2017_codes.add('010401','MTS - PCO')
        $ADP_2017_codes.add('010402','MTS - READINESS, SUSTAINMENT, INDUSTRIAL OP')
        $ADP_2017_codes.add('010403','MTS - MODERNIZATION & TECHNOLOGY DEPLOYMENT')
        $ADP_2017_codes.add('010404','MTS - ADVANCED ENGINEERING & BUSINESS SOLUTIONS OP')
        $ADP_2017_codes.add('010405','MTS - ACQUISITION PROG & TRAINING SOLUTIONS OP')
        $ADP_2017_codes.add('010406','MTS - SURFACE STRATEGY & MAINTENANCE INTEGRATION OP')
        $ADP_2017_codes.add('010407','MTS - STRATEGIC SOLUTIONS CENTER')
        $ADP_2017_codes.add('10153','CABRILLO FS GROUP')
        $ADP_2017_codes.add('015300','CAB FS - GRP MGMT')
        $ADP_2017_codes.add('015301','CAB FS - OPERATION')
        $ADP_2017_codes.add('10154','MCKEAN FS TECHNICAL SERVICES GROUP')
        $ADP_2017_codes.add('015400','MTS FS - GRP MGMT')
        $ADP_2017_codes.add('015401','MTS FS - PCO')
        $ADP_2017_codes.add('015402','MTS FS - READINESS, SUSTAINMENT, INDUSTRIAL OP')
        $ADP_2017_codes.add('015403','MTS FS - MODERNIZATION & TECHNOLOGY DEPLOYMENT')
        $ADP_2017_codes.add('015404','MTS FS - ADVANCED ENGINEERING & BUSINESS SOLUTIONS OP')
        $ADP_2017_codes.add('015405','MTS FS - ACQUISITION PROG & TRAINING SOLUTIONS OP')
        $ADP_2017_codes.add('015406','MTS FS - SURFACE STRATEGY & MAINTENANCE INTEGRATION OP')
        $ADP_2017_codes.add('015407','MTS FS - STRATEGIC SOLUTIONS CENTER')
        $ADP_2017_codes.add('10190','CORP')
        $ADP_2017_codes.add('019000','CORP - OPERATIONS')
        $ADP_2017_codes.add('019001','CORP - HUMAN RESOURCES')
        $ADP_2017_codes.add('019002','CORP - MARKETING & BD')
        $ADP_2017_codes.add('019003','CORP - BUSINESS SERVICES')
        $ADP_2017_codes.add('019004','CORP - INFORMATION TECHNOLOGY')
        $ADP_2017_codes.add('019005','CORP - FINANCE')
        $ADP_2017_codes.add('019006','CORP - CONTRACTS')
        $ADP_2017_codes.add('10195','CORP FS')
        $ADP_2017_codes.add('019500','CORP FS - OPERATIONS')
        $ADP_2017_codes.add('019501','CORP FS - HUMAN RESOURCES')
        $ADP_2017_codes.add('019502','CORP FS - MARKETING & BD')
        $ADP_2017_codes.add('019503','CORP FS - BUSINESS SERVICES')
        $ADP_2017_codes.add('019504','CORP FS - INFORMATION TECHNOLOGY')
        $ADP_2017_codes.add('019505','CORP FS - FINANCE')
        $ADP_2017_codes.add('019506','CORP FS - CONTRACTS')
        $ADP_2017_codes.add('102','AG224')
        $ADP_2017_codes.add('10201','CABRILLO GROUP')
        $ADP_2017_codes.add('1020100','CAB - GRP MGMT')
        $ADP_2017_codes.add('1020101','CAB - OPERATION')
        $ADP_2017_codes.add('NEW','CABRILLO FS GROUP')
        try{$ADP_2017_codes.add('NEW','CAB FS - GRP MGMT')}catch{} #error cannot have a duplicate 'NEW'
        try{$ADP_2017_codes.add('NEW','CAB FS - OPERATION')}catch{} #error cannot have a duplicate 'NEW'
        #endregion ADP_2017_codes
        #endregion BaseVariables
    
    } # Begin

    Process {
        #region SelectTheCSV
        try {
            $TheCSV= Get-Filename `
            -Title "Select CSV file to process"  `
            -Filter 'CSV Files (*.csv)|*.csv|Excel Files (*.xl*)|*.xlx*|All Files (*.*)|*.*' `
            -initialDirectory $(split-path -parent $MyInvocation.MyCommand.Definition)
            } #try
        catch {
            Write-Host "Nothing selected!" -ForegroundColor Yellow } #catch
        #endregion SelectTheCSV
        #region Exit_If_Nothing_Selected
        if ($TheCSV -eq "") <# 20150801 Added code to abort processing if no file was selected #>
            { Write-host "Nothing to process, exiting script." -ForegroundColor Yellow
            rv * -ea 0
            Write-Host "Goodbye."  -ForegroundColor Yellow
            exit }
        else {
            $TheCSV = Get-Item $TheCSV 
            #$RunLog = ($TheCSV.DirectoryName,'logs',($theCSV.basename,'run.log' -join '-') -join '\'
            $Logfile = $TheCSV.DirectoryName,'logs',($theCSV.basename,'run.log' -join '-') -join '\'
            }
        #endregion Exit_If_Nothing_Selected
        $UD=Import-Csv $TheCSV
        #region Exit-if-NOT-old-format
            if ($(Get-HRBformat -csvData $UD) -ne 'Old Format') 
            { $msg = 'The selected CSV file is not in the proper format. Exiting.'
                Write-LogError -Message $msg -LogPath $Logfile -ToScreen -TimeStamp
                $mail.subject = "HRB Input: '$($thecsv.BaseName)' is not properly formatted."
                if (Test-Path $Logfile){$mail.attachments = $Logfile}
                $mail.body=$mail.body.ToString()
                Send-MailMessage @mail
                Write-Host "Goodbye."
                rv * -ea 0
                exit }
        #endregion Exit-if-NOT-old-format
        #region MailBodyHeading
        $Mail.body += "====================================="
        $Mail.body += "HRB Import Script v.$(Get-ScriptVersion)"
        $Mail.body += "====================================="
        $Mail.body += "Begin Processing $($TheCSV.BaseName)"
        $Mail.body += "====================================="
        $Mail.body | Out-String
        #endregion MailBodyHeading
        #region MainLoop
        foreach ($U in $UD){
            #region common
            #region SkipTestUsers
                if ($TestEmplIDs -contains $u.'Employee Id') {
                $msg = "Skipping $u.'first name' $u.'Last Name' $u.'Employee Id'"
                Write-LogInfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                $MailBody = $MailBody,$msg -join $cr
                $Counts.Skipped++
                continue }
            #endregion SkipTestUsers
            #endregion common
            #region Process Adds
            if ($u.tx -eq 'A' -and !(($TheCSV.Name -like 'term*'))) 
                { #if ($u.tx -eq 'A' -and !(($TheCSV.Name -like 'term*')))
                    write-verbose " $(Get-Date -displayhint date) A"
                    if ((get-aduser -filter "employeeID -like '$($U."Employee ID")'" -SearchBase $TheSrchBase -properties *) -eq $null)
                    {
                        $tmpSamAccountName = New-UniqueSAMName -lname $u.'Last Name' -FName $u.'First Name' -MI $u.'Middle Name'
                        $NewUserName="$($U."Last Name"), $($U."First Name") "
                        if ($($u."Middle Name".length -gt 0))
                        {
                            $NewUserName=($NewUserName + " $($u."Middle Name".substring(0,1)).").trim()
                        } #if ($($u."Middle Name".length -gt 0))
                        $msg = "New User, Empl #: $($u.employeeid), $($u.'First Name') $($u.'Last Name') -- Logon: $newUserName"
                        Write-LogInfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen

                        $NewUserPassword=("McKean-$($U."Employee ID")").trim()
    
                        try # to create new user
                        {
                            #2012-12-21 -- Modified -path to ensure new users are created in the proper OU for auto mailbox creation
                            Write-Host "Trying to create New User, Empl #: $($u.employeeid), $($u.'First Name') $($u.'Last Name') -- Logon: $newUserName" -ForegroundColor Green
                            New-ADUser -SamAccountName $tmpSamAccountName -Name $newUserName -DisplayName $NewUserName `
                            -EmployeeID $($U."Employee ID").trim() -enabled $true -givenName $($U."First Name").trim() `
                            -surname $($U."Last Name") -path "ou=users,ou=mckean,dc=mckean,dc=local" `
                            -UserPrincipalName $tmpSamAccountName"@mckean.local" `
                            -AccountPassword  (ConvertTo-SecureString -AsPlainText $NewUserPassword -Force)

                            $Counts.NewUsers++
                            $i-=1
                            $msg =  "Added EmplID: $($U."Employee ID") - $newUserName "

                            Write-LogInfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen

                            $MailBody = $($MailBody),$msg -join $cr
                        } #try to create new user
    
                        catch #failure when creating new user
                        {
                            $msg =  "Unable to create user: $($NewUserName)"
                            $msg =  "NOT Added - EmplID: $($U."Employee ID").trim() - $($U."Last Name").trim(), $($U."First Name").trim [EmplID already exists]."
                            Write-LogInfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                            $u.tx="C"
                        } #catch failure when creating new user
    
                        } # if ((get-aduser -filter "employeeID -like '$($U."Employee ID")'" -SearchBase $TheSrchBase -properties *) -eq $null)
    
            else {
                #20120606:Added/modified various status lines
                # write-host "NOT Added - EmplID: $($U."Employee ID") - $($U."Last Name"), $($U."First Name") [EmplID already exists]"
                # -- 20120621.1
                $msg= "NOT Added - EmplID: $($U."Employee ID") - $($U."Last Name"), $($U."First Name") [EmplID already exists]."
                Write-LogWarning -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                $MailBody = $($MailBody),$msg -join $cr
                $iNoAdds++    #20120606.1:Added feature to count NoAdds (already Present)
                } #else
    
                } #if ($u.tx -eq 'A' -and !(($TheCSV.Name -like 'term*')))
            #endregion Process Adds
            #region Process Deletions
            if  (($u.tx -eq 'D') -or  ($TheCSV.Name -like 'terms*')) {
                $msg= "Disabling EmplID: $([string][int]$U.'Employee ID') - $($U.'Last Name'), $($U.'First Name')"
                Write-LogInfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                $MailBody = $MailBody,$msg -join $cr
                #region FindAllMatchingUsers
                $usrs2dis=@(get-aduser -filter "employeeID -like '$([string][int]$U.'Employee ID')*'" -properties *)
                #endregion FindAllMatchingUsers
                #region ProcessAllMatchingUsers
                if($usrs2dis)
                    { 
                    #region Disable
                    foreach ($usr in $usrs2dis) {
                        if ($usr.enabled -eq $false) {
                            $msg= "[Previously disabled: $($usr.description)]"
                            $Counts.NotDisabled+=1
                            } # ($usr.enabled -eq $false)
                        else {
                            $msg= "Disabling '$($usr.samaccountname)'"
                            try {
                                $usr.Enabled=$FALSE
                                Set-ADUser -Instance $usr
                                Write-LogInfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                                $MailBody = $MailBody,$msg -join $cr 
                                $Counts.DisUsers += 1}
                            catch {
                                Write-LogInfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                                $MailBody = $MailBody,$msg -join $cr
                                $msg= "Could not disable '$($usr.samaccountname)'"
                                Write-LogError -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                                $MailBody = $MailBody,$msg -join $cr}
                        } # else
                        } #foreach ($usr in $usrs2dis)
                    #endregion Disable
                    #region UpdateDescr
                    try {
                        $msg= "Updating disabled description"
                        if($usr.Description -match "TERMED per HRB") {
                            $msg= "Description already contained 'TERMED per HRB' "
                            Write-LogInfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                            $MailBody = $MailBody,$msg -join $cr 
                            } #if($usr.Description -match "TERMED per HRB")
                        else {
                            $usr.description="TERMED per HRB: $($TheCSV.BaseName)"
                            Set-ADUser -Instance $usr
                            Write-LogInfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                            $MailBody = $MailBody,$msg -join $cr 
                            } #else
                    } #try
                    catch {
                            $msg= "Could not update the description for: '$($usr.samaccountname)'"
                            Write-LogError -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                            $MailBody = $MailBody,$msg -join $cr
                            } #catch
                    #endregion UpdateDescr
                    #region Expire
                    try {
                        $msg= "Updating Account Expiration to $(((Get-Date).date).AddDays(-7).ToString('yyyy-MMM-dd').ToUpper())"
                        $usr.AccountExpirationDate=([datetime](Get-Date).date).AddDays(-7)
                        Set-ADUser -Instance $usr
                        Write-LogInfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                        }
                    catch {
                        $msg= "Could not update the account expiration for: '$($usr.samaccountname)'"
                        Write-LogError -Message $msg -LogPath $Logfile -TimeStamp -ToScreen 
                        }
                    $MailBody = $MailBody,$msg -join $cr
                    #endregion Expire
                    #region NoMoreVPN
                    try {
                        if($usr.msNPAllowDialin -eq $FALSE) {
                            $msg= " VPN Access already terminated."
                            Write-LogInfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                            $MailBody = $MailBody,$msg -join $cr 
                            } # if
                        else {
                            $msg= " Disabling VPN access for '$($usr.samaccountname)'"
                            $usr.msNPAllowDialin=$false
                            Set-ADUser -Instance $usr
                            Write-LogInfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen 
                            } # else
                    } # try
                    catch {
                        $msg= " Could not disable VPN access for: '$($usr.samaccountname)'"
                        Write-LogError -Message $msg -LogPath $Logfile -TimeStamp -ToScreen 
                    } # catch
                    $MailBody = $MailBody,$msg -join $cr
                    #endregion NoMoreVPN
                    #region RandomizePassword
                    $RandomPass=[Web.Security.Membership]::GeneratePassword(32,16)
                    $msg= " Randomizing passwoord for '$($usr.samaccountname)'"
                    try {
                        Set-ADAccountPassword -Identity $($usr.DistinguishedName) -Reset -NewPassword (ConvertTo-SecureString $($RandomPass) -AsPlainText -Force)
                        Write-LogInfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen 
                        } # try
                    catch {
                        $msg= " Unable to randomize for '$($usr.samaccountname)'"
                        Write-LogError -Message $msg -LogPath $Logfile -TimeStamp -ToScreen 
                        } # catch
                    $MailBody = $MailBody,$msg -join $cr
                    #endregion RandomizePassword
                    #region MoveToTermed
                    if ($usr.DistinguishedName  -match $TermedBase) {
                        $msg= " '$($usr.samaccountname)' is already in the 'Termed' OU"
                        Write-LogInfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen 
                        } #if
                    else {
                        try { 
                            Move-ADObject -TargetPath $TermedBase -Identity $usr.DistinguishedName
                            $msg= "'$($usr.samaccountname)' moved to $TermedBase"
                            Write-Loginfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                            $MailBody = $MailBody,$msg -join $cr 
                            } #try
                        catch {
                            $msg= "Failed to move '$($usr.samaccountname)' to $TermedBase"
                            Write-LogError -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                            $MailBody = $MailBody,$msg -join $cr 
                            } #catch
                        } #else
                    #endregion MoveToTermed
                    }
                #endregion ProcessAllMatchingUsers
                #region NoMatchingUsers
                else {
                    $msg= "Unable to locate EmplID: $([string][int]$U.'Employee ID') - $($U.'Last Name'), $($U.'First Name')"
                    Write-LogError -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                    $MailBody = $MailBody,$msg -join $cr
                    } #else
                #endregion NoMatchingUsers
                rv usrs2dis
            }
            #endregion Process Deletions
            #region NoAction
            if ($u.tx -eq "-") {  #No Action
                $msg="Skipped EmplID: $($U."Employee ID") - $($U."Last Name"), $($U."First Name")"
                Write-LogInfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                $MailBody = $MailBody,$msg -join $cr
                $Counts.Skipped++ }
            #endregion NoAction

            #region Process Changes/Updates
            if (!($U.TX) -or $u.tx -eq 'C' -or $u.TX -eq 'A' -and !(($TheCSV.Name -like 'term*'))) {
                $msg="Attempting to process EmplID: $($U."Employee ID") - $($U."Last Name"), $($U."First Name")"
                Write-LogInfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                #$usrs2upd=get-aduser -filter "employeeID -like '$($U.'Employee ID')*'" -SearchBase $TheSrchBase -properties *
                try {
                    $usrs2upd=@(get-aduser -filter "employeeID -like '$([string][int]$U.'Employee ID')*'" -Properties *)
                    $msg="Located $($usrs2upd.count) matching accounts"
                    Write-LogInfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                    }
                catch {
                    $usrs2upd=@(get-aduser -filter "employeeID -eqlike '$([string][int]$u.'Associate ID')*'" -Properties *) 
                    $msg="Located $($usrs2upd.count) matching accounts"
                    Write-LogInfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                    }

                foreach($usr in $usrs2upd) {
                    #region UpdStart
                    $usr=get-aduser $usr.SamAccountName -Properties *
                    $msg=" Updating user $($usr.name) [$($usr.samaccountname)]"
                    Write-LogInfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                    $MailBody = $MailBody,$msg -join '`r`n'
                    #endregion UpdStart
                    #region UpdName
                    $newFirstName=$u.'First Name'.Replace(".","").replace("-","").replace(" ","").replace("'","").trim()
                    $newLastName=$u.'Last Name'.Replace(".","").replace("-","").trim()
                    if($u.'Middle Name' -ne '') {
                        $newMI=$u.'Middle Name'.trim().substring(0,1)
                        }
                    $newCN="$newLastName, $newFirstName"
                    #region UpdGivenName
                    if($usr.GivenName -ne $newFirstName) {
                        try {
                            $usr.GivenName=$newFirstName
                            Set-ADUser -Instance $usr
                            $msg=" Updated first name to '$($newFirstName)'"
                            Write-Loginfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                            $MailBody = $MailBody,$msg -join '`r`n' 
                            } # try
                        catch {
                            $msg=" Failed to first name to '$($newFirstName)'"
                            Write-LogError -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                            $MailBody = $MailBody,$msg -join '`r`n' 
                            } #catch
                        } #if
                    else {
                        $msg=" No Change in First Name"
                        Write-Loginfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                        $MailBody = $MailBody,$msg -join '`r`n' 
                        } #else
                    #endregion UpdGivenName
                    #region UpdSurName
                    if($usr.Surname -ne $newLastName) {
                        try {
                            $usr.Surname = $newLastName
                            Set-ADUser -Instance $usr
                            $msg=" Updated last name to '$($newLastName)'"
                            Write-Loginfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                            $MailBody = $MailBody,$msg -join '`r`n' 
                            } #try
                        catch {
                            $msg=" Failed to update last name to '$($newLastName)'"
                            Write-LogError -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                            $MailBody = $MailBody,$msg -join '`r`n' 
                            } #catch
                        } #if
                    else {
                        $msg=" No Change in Last Name"
                        Write-Loginfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                        $MailBody = $MailBody,$msg -join '`r`n' 
                        }#else
                    #endregion UpdSurName
                    #region UpdMI
                    if ($($usr.initials) -ne $newMI) {
                        try {
                            $usr.Initials = $newMI
                            Set-ADUser -Instance $usr
                            $msg=" Updated middle initial to '$($newMI)'"
                            Write-Loginfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                            $MailBody = $MailBody,$msg -join '`r`n' 
                            } #try
                        catch {
                            $msg=" Failed to update middle initial to '$($newMI)'"
                            Write-LogError -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                            $MailBody = $MailBody,$msg -join '`r`n' 
                            } #catch
                        } #if
                    else {
                        $msg=" No Change in Middle Initial"
                        Write-Loginfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                        $MailBody = $MailBody,$msg -join '`r`n' 
                        } #else
                    #endregion UpdMI
                    #region UpdCN
                    if ($usr.cn -ne $newCN)
                    {try
                        {Rename-ADObject $usr.ObjectGUID -newname $newCN
                        $usr=Get-ADUser $usr.ObjectGUID
                        $msg=" Updated CN to $newCN"
                        Write-LogInfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                        $MailBody = $MailBody,$msg -join '`r`n'
                        }
                    catch
                        {$msg=" Failed Updating CN to $newCN"
                        Write-LogError -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                        $MailBody = $MailBody,$msg -join '`r`n'
                        }
                    }
                    else
                    {$msg=" No change needed to CN '$($newCN)'"
                    Write-Loginfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                    $MailBody = $MailBody,$msg -join '`r`n' } 
                    #endregion UpdCN
                #endregion UpdName
                #region UpdEmail
                    $properemailaddress=($($usr.SamAccountName) + 
                    $(if($usr.Department -like "cab*")
                        {"@cabrillotechnologies.com"}
                        else
                        {"@mckean-defense.com"}
                        )
                    )
                    if ($usr.mail -ne $properemailaddress) 
                    {try
                    {$usr.mail = $properemailaddress
                        Set-ADUser -Instance $usr
                        $msg=" Updated email address to '$($properemailaddress)'"
                        Write-Loginfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                        $MailBody = $MailBody,$msg -join '`r`n' }
                    catch
                    {$msg=" Failed to update email address to '$($properemailaddress)'"
                        Write-LogError -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                        $MailBody = $MailBody,$msg -join '`r`n' } }
                    else
                    {$msg=" Email address appears correct"
                    Write-Loginfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                    $MailBody = $MailBody,$msg -join '`r`n' } 
                #endregion UpdEmail
                #region UpdDialIn
                    try
                    {$usr.msNPAllowDialin = $true 
                    Set-ADUser -Instance $usr
                    $msg=" Enabling Remote (VPN) Access"
                    Write-LogInfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                    $MailBody = $MailBody,$msg -join '`r`n'}
                    catch
                    {$msg=" Could not enable Remote (VPN) Access"
                    Write-LogError -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                    $MailBody = $MailBody,$msg -join '`r`n' } 
                #endregion UpdDialIn
                #region UpdManager
                    try
                    {$uMgr=(get-aduser -filter "employeeID -eq '$([string][int]$U.'Manager ID')'" -Properties *)}
                    catch
                    {$uMgr=(get-aduser -filter "employeeID -eq '$([string][int]$u.'Reports To Associate ID')'" -Properties *) }

                    if ($uMgr)
                    {
                    #region PWReset_Supervisor
                    try{
                    $usr.EmployeeNumber = $uMgr.Surname.ToUpper()
                    set-aduser -Instance $usr
                    $msg=" Updated PWReset supervisor to $($uMgr.Surname.ToUpper())"
                    Write-LogInfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                    $MailBody = $MailBody,$msg -join '`r`n'
                    }
                    catch{
                    $msg=" Could not update PWReset supervisor"
                    Write-LogError -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                    $MailBody = $MailBody,$msg -join '`r`n'
                    }
                    #endregion PWReset_Supervisor
               
                    #region AD_Manager
                    try{
                    $usr.Manager = $uMgr.distinguishedname
                    set-aduser -Instance $usr
                    $msg=" Updated AD Manager to $($uMgr.name)"
                    Write-LogInfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                    $MailBody = $MailBody,$msg -join '`r`n'
                    }
                    catch{
                    $msg=" Could not update AD Manager"
                    Write-LogError -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                    $MailBody = $MailBody,$msg -join '`r`n'
                    }
                    #endregion AD_Manager
                    }
                    else
                    {$msg=" Could not locate a manager with employee id: '$(if($u.'manager id'){[string][int]$u.'manager id'}else{[string][int]$u.'Reports To Associate ID'})'"
                    Write-LogError -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                    $MailBody = $MailBody,$msg -join '`r`n'
                    }
                #endregion UpdManager
                #region UpdDeptName
                    $newDeptName=if($u.'manager id'){$u.'Home Department'}else{$u.'Home Department Description'}
                    if ($usr.department -ne $newDeptName)
                    {
                    try 
                    {$usr.department = $newDeptName
                    set-aduser -Instance $usr
                    $msg=" Updated Department to $($newDeptName)"
                    Write-LogInfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                    $MailBody = $MailBody,$msg -join '`r`n' }
                    catch
                    {$msg=" Could not update Department $($newDeptName)"
                    Write-LogError -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                    $MailBody = $MailBody,$msg -join '`r`n' }
                    } 
                #endregion UpdDeptName
                #region UpdCompany
                    if ($U.'Employee ID'.substring(0,1) -eq '9') { $TheCoField = 'CRI'}
                    else { $TheCoField='McKean Defense' }
             
                    if ($usr.company -ne $TheCoField)
                    {try
                    {
                    $usr.Company=$TheCoField
                    Set-ADUser -Instance $usr
                    $msg=" Updated Company to $($TheCoField)"
                    Write-LogInfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                    $MailBody = $MailBody,$msg -join '`r`n'
                    }
                    catch
                    {$msg=" Could not update Department $($u.'Home Department')"
                    Write-LogError -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                    $MailBody = $MailBody,$msg -join '`r`n' }
                    }
                    else
                    {$msg=" No Change in Company Name"
                    Write-Loginfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                    $MailBody = $MailBody,$msg -join '`r`n' }
                #endregion UpdCompany
                #region UpdOfficeLocation
                    if ($usr.office -ne $U.location) 
                    {try
                    {$usr.Office=$($u.'Location')
                    Set-ADUser -Instance $usr
                    $msg= " Updating Office to '$($U.location)'"
                    Write-LogInfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                    $MailBody = $MailBody,$msg -join '`r`n'}
                    catch
                    {$msg=" Could not update office location to $($u.'location')"
                    Write-LogError -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                    $MailBody = $MailBody,$msg -join '`r`n' } }
                    else
                    {$msg=" No Change in Office location"
                    Write-Loginfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                    $MailBody = $MailBody,$msg -join '`r`n' }
                #endregion UpdOfficeLocation
                #region UpdOfficePhone
                    if (($u.'Work Phone'.length -ne 0 ) -and 
                        ($usr.OfficePhone -ne $($u.'Work Phone')) )
                    {try
                    {$usr.OfficePhone=$($u.'Work Phone')
                    Set-ADUser -Instance $usr
                    $msg= " Updated OfficePhone to '$($U.'Work Phone')'"
                    Write-LogInfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                    $MailBody = $MailBody,$msg -join '`r`n'}
                    catch
                    {$msg=" Could not update OfficePhone to '$($U.'Work Phone')'"
                    Write-LogError -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                    $MailBody = $MailBody,$msg -join '`r`n' } }
                    else
                    {$msg=if($u.'Work Phone'.length -eq 0 ){" There is no OfficePhone listed"}else{" No Change in OfficePhone"}
                    Write-LogInfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                    $MailBody = $MailBody,$msg -join '`r`n' }
                #endregion UpdOfficePhone
                #region UpdDeptNo
                    #$UD[1].'Home Department Code'.Replace('.','').padright(7,' ').substring(2,5)
                    $dcode=if($u.'Home Department Code'.contains('.'))
                    {[string][int]$U.'Home Department Code'.Replace('.','').padright(7,' ').substring(2,5)}
                    else{[string][int]$U.'Home Department Code'}
                    #$dcode
                    if ($usr.departmentnumber -ne $dcode) 
                    {
                    try
                        {
                            $usr.departmentnumber = $dcode
                            Set-ADUser -Instance $usr
                            $msg= " Updated Department ## to '$($dcode)'[$($u.'Home Department Code')]"
                            Write-LogInfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                            $MailBody = $MailBody,$msg -join '`r`n'
                        } #try
                    catch {
                        $msg= " Failed Updating Department ## to '$($dcode)'[$($u.'Home Department Code')]"
                        Write-LogError -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                        $MailBody = $MailBody,$msg -join '`r`n' 
                    } #catch
                    } #if ($usr.departmentnumber -ne $dcode)
                    else {
                    $msg=" No Change in Dept Number '$($dcode)'[$($u.'Home Department Code')]"
                    Write-Loginfo -Message $msg -LogPath $Logfile -TimeStamp
                    $MailBody = $MailBody,$msg -join '`r`n' 
                    } #else ($usr.departmentnumber -eq $dcode)
                #endregion UpdDeptNo
                #region UpdHomeZip
                    $HomeZip=$(($u."Zip/Postal Code".PadLeft(5,"0")).substring(0,5))
                    if ($usr.carLicense -ne $HomeZip) 
                    {try
                    {$usr.carLicense = $HomeZip
                    Set-ADUser -Instance $usr
                    $msg=" Updated Home zipcode to '$($HomeZip)'"
                    Write-LogInfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                    $MailBody = $MailBody,$msg -join '`r`n'}
                    catch
                    {$msg=" Could not update Home zipcode to '$($HomeZip)'"
                    Write-LogError -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                    $MailBody = $MailBody,$msg -join '`r`n' } }
                    else
                    {$msg=" No Change in Home zipcode '$($HomeZip)'"
                    Write-Loginfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                    $MailBody = $MailBody,$msg -join '`r`n' }
                    rv HomeZip
                #endregion UpdHomeZip
                #region UpdEmplDOB
                    #stored in 'employeetype'
                    #$dob=([datetime]$u.'date of birth').tostring('dd')
                    Write-Verbose $u.'Date of Birth' -Verbose
                    $dob = &{ if (  $u.'Date of Birth'.Length -le 2 -and 
                            [int]$u.'Date of Birth' -ge 1 -and 
                            [int]$u.'Date of Birth' -le 31)
                            {([int]$u.'Date of Birth').tostring('00')}
                            else{([datetime]$u.'date of birth').tostring('dd')}
                            }
                    if ($usr.employeeType -ne $dob) {
                    try
                    {$usr.employeeType = $dob
                    Set-ADUser -Instance $usr
                    $msg=" Updating Date of birth"
                    Write-LogInfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                    $MailBody = $MailBody,$msg -join '`r`n'}
                    catch
                    {$msg=" Could not update Date of birth"
                    Write-LogError -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                    $MailBody = $MailBody,$msg -join '`r`n' }
                    rv dob
                    } #if ($usr.employeeType -ne $dob)
                #endregion UpdEmplDOB
                #region Description
                    $desc="HRB: $($TheCSV.BaseName) $($RunTime)"
                    try
                    {$usr.Description = $desc
                    Set-ADUser -Instance $usr
                    $msg=" Updated Description"
                    Write-LogInfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                    $MailBody = $MailBody,$msg -join '`r`n'}
                    catch
                    {$msg=" Could not update Description"
                    Write-LogError -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
                    $MailBody = $MailBody,$msg -join '`r`n' }
                    rv desc
                #endregion Description
                $i++
                } #foreach($usr in $usrs2upd)
                } #if (!($U.TX) -or $u.tx -eq 'C' -or $u.TX -eq 'A')
            #endregion Process Changes/Updates

        } #$U in $UD
        #endregion MainLoop
        #region Clean_up_AD_Dynamic_Department_Groups
            $GrpList=Get-ADGroup -filter {name -ne 'HRB-Managers' -and name -ne 'HRB-Executives' } -SearchBase $($SPGroupOU) -SearchScope Subtree -Properties *
            <# the following code block creates a summary of current group member counts
                {
                Get-ADGroup -filter {name -ne 'HRB-Managers' -and name -ne 'HRB-Executives' } -SearchBase $($SPGroupOU) -SearchScope Subtree -Properties * |
                ft @{name="Dept Code";expression={$_.samaccountname -replace 'HRB-DPT-', ''}},
                    @{name="Dept Name";expression={$_.cn -replace 'HRB-DEPT-', ''}},
                    @{name="Member Count";expression={(get-adgroupmember $_.samaccountname).name.count}} -AutoSize | out-file $Logfile -Encoding string -Append
                gc $logfile
                }
                i.e.:
                Dept Code Dept Name Member Count
                --------- --------- ------------
                1.01 EOM 0
                1.01.01 RSS BU 0
                1.01.01.00 RSS - OPS MGMT 0
                1.01.01.01 RSS - MID ATLANTIC 0
                1.01.01.02 RSS - PACIFIC 0
                1.01.01.03 RSS - WATERFRONT SUPPT 0
                1.01.01.04 RSS - NAVSEA 0
                1.01.01.05 RSS - SURFMEPP 0
                1.01.01.06 RSS - PROJ MGMT 0
                1.01.02 STS BU 0
                1.01.02.00 STS - OPS MGMT 0
                1.01.02.01 STS - IT SERVICES 0
                1.01.02.02 STS - MATERIALS & MACHINERY 2
                1.01.02.03 STS - ENGINEERING SERVICES 0
                1.01.02.04 STS - INTEGRATED FLEET SERVICES 2
                1.01.02.05 STS - CRANE 0
                1.01.02.06 STS - PROJ MGMT 0
                1.01.03 Cabrillo BU 0
                1.01.03.00 CAB - OPS MGMT 0
                1.01.03.01 CAB - OPERATIONS 1
                1.01.51 RSS FS BU 0
                1.01.51.00 RSS FS - OPS MGMT 0
                1.01.51.01 RSS FS - Mid Atlantic 0
                1.01.51.02 RSS FS - PACIFIC 0
                1.01.51.03 RSS FS - WATERFRONT SUPPT 0
                1.01.51.04 RSS FS - NAVSEA 1
                1.01.51.05 RSS FS - SURFMEPP 0
                1.01.52 STS FS BU 0
                1.01.52.00 STS FS - OPS MGMT 0
                1.01.52.01 STS FS - IT Services 0
                1.01.52.02 STS FS - Materials & Machinery 0
                1.01.52.03 STS FS - Engineering Services 0
                1.01.52.04 STS FS - Integrated Fleet Services 0
                1.01.52.05 STS FS - CRANE 0
                1.01.90 Corporate 0
                1.01.90.00 CORP - OPERATIONS 0
                1.01.90.01 CORP - HUMAN RESOURCES 1
                1.01.90.02 CORP - MARKETING & BD 0
                1.01.90.03 CORP - BUSINESS SERVICES 0
                1.01.90.04 CORP - INFORMATION TECHNOLOGY 0
                1.01.90.05 CORP - FINANCE 16
                1.01.90.06 CORP - CONTRACTS 0
                1.02 New Payroll Code 0
                1.02.01 Cabrillo Technologies 0
                1.02.01.00 Cabrillo - HQ 0
                1.06 MCKEAN IT 0
            #>
 #code block creates a summary of current group member counts
            $msg="Updating $($grpList.count) Dynamic Department Groups"
            Write-LogInfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
            $MailBody = $MailBody,$msg -join $cr
                                                                                                                                                                                                                                                                                                                                                            #region ProcessTheGroupList
      foreach ($Grp in $GrpList)
       {
          #region GetDeptNo
            #.SamAccountName.Replace('HRB-Dpt-','').replace('.','').padright(7,'0').substring(2,5)
           $DeptNo=$(($Grp.samaccountname).replace('HRB-Dpt-','').replace('.','').padright(7,'0').substring(2,5))
          #endregion GetDeptNo
          #region get-initialMemberCount
           $initialMemberCount = (Get-ADGroupMember $Grp.distinguishedname).name.count
           #--- $initialMemberCount = $(if ($initialMemberCount -eq $null){"0"}else{$initialMemberCount})
          #endregion get-initialMemberCount
          #region dePopulate-the-group
           #First, empty the group (http://stackoverflow.com/questions/26303857/powershell-remove-all-users-from-a-specific-group)
           Get-ADGroupMember $Grp.distinguishedname | ForEach-Object {Remove-ADGroupMember $Grp.distinguishedname $_ -Confirm:$false}
          #endregion dePopulate-the-group
          #region RE-populate-the-group
           #Select users from the McKean Users OU to the group that have the user.departmentNumber property equal to $DeptNo
           Get-ADUser -Filter { departmentNumber -eq $DeptNo } -SearchBase $ActvUsrOU -SearchScope Subtree | 
             ForEach-Object {Add-ADGroupMember $Grp.distinguishedname $_.distinguishedname -Confirm:$false}
          #endregion RE-populate-the-group
          #region get-FinalMemberCount
           $finalMemberCount = (Get-ADGroupMember $Grp.distinguishedname).name.count
           #----$finalMemberCount = $(if ($finalMemberCount -eq $null){"0"}else{$finalMemberCount})
          #endregion get-FinalMemberCount
          $msg="Group '$($Grp.name)' -- from $($initialMemberCount) -> $($finalMemberCount) members."
          Write-LogInfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
          $MailBody = $MailBody,$msg -join $cr
         }
     #endregion ProcessTheGroupList
        #endregion Clean_up_AD_Dynamic_Department_Groups
        #region Check-for-users-without-descriptions
         Write-LogInfo -Message ' ' -LogPath $Logfile -ToScreen
         if ($NoDescrUsers){
           $msg="We are still missing information for the following users:"
           Write-LogInfo -Message $msg -LogPath $Logfile -ToScreen
           foreach($ndu in $NoDescrUsers){
             $msg= $ndu.employeeid,$ndu.name -join $tab
             Write-LogInfo -Message $msg -LogPath $Logfile -ToScreen}
           }
         else
          {$msg="All active AD users have descriptions."
           Write-LogInfo -Message $msg -LogPath $Logfile -TimeStamp -ToScreen
           $MailBody = $MailBody,$msg -join $cr }
        #endregion Check-for-users-without-descriptions
        #region AddSummaryToLogFile
        $sum=@"
=====================================
$($thecsv.BaseName) Processing Complete!
=====================================
Newly Disabled: $($Counts.DisUsers)
Already Disabled: $($NotDisabled)
New Adds: $($Counts.NewUsers)
Already Added: $($iNoAdds)
Updated: $($i)
SKIPPED/ERRORS: $($Counts.Skipped)
=====================================
Records Processed: $($ud.count)
=====================================
"@

        $sum|Out-File $Logfile -Append -encoding string
        #endregion AddSummaryToLogFile
        #region NotificationEmail
        $mail.subject = "$($TheCSV.BaseName) Processing Report".ToString()
        $mail.body    = ('#assign dmurray','#mute','#close',$Sum)|out-string
        if (Test-Path $Logfile){$mail.attachments = $Logfile}
        Write-Host starting send
        Send-MailMessage @mail
        Write-Host complete!
        #endregion NotificationEmail
        #region MoveTheCSV
         try {
            $dest = ($TheCSV.DirectoryName,'completed',($RunDate,$TheCSV.BaseName -join ',') -join '\'),(get-item $TheCSV).Extension -join ''

            move-item -Path $TheCSV.FullName -Destination $dest
            rv dest
            } # try
         Catch {
            $msg="Unable to relocate the '$($TheCSV.basename)' file to '$($TheCSV.DirectoryName),'complete' -join '\')'"
            $mail.subject =$msg
            $mail.body    = ('#assign dmurray','#mute','#close',$msg|Out-String)
            $mail.Remove('attachments')
            Send-MailMessage @mail
            } # Catch
         Finally{}
        #endregion MoveTheCSV
    } # Process

    End {
        $RunMsgSplat.body = (
            $RunMsgSplat.body,
            " ===================================== ",
            " $($scriptName) Processing Complete! ",
            " ===================================== ",
            " Newly Disabled: $($Counts.DisUsers) ",
            " Already Disabled: $($NotDisabled) ",
            " New Adds: $($Counts.NewUsers) ",
            " Already Added: $($iNoAdds) ",
            " Updated: $($i) ",
            " SKIPPED/ERRORS: $($Counts.Skipped) ",
            " ===================================== ",
            " Records Processed: $($ud.count) ",
            " ===================================== " 
           ) | Out-String
        Send-MailMessage @$RunMsgSplat
    } # End
}
#region MyLogfileName
$MyLogfileName = {
    if (((Get-PSCallStack)[(Get-PSCallStack).count-1].Location -eq '<No file>')) {
        "Interactive",
        (get-date).tostring('yyyyMMddHHmmss'),
        'log' -join '.'
        }
    else {
        ((Get-PSCallStack)[0].command,
        (get-date).tostring('yyyyMMddHHmmss'),
        'log') -join '.'
        }
    }
#endregion MyLogfileName
#region RandomPasswordGeneration
    Add-Type -Assembly System.Web 
#endregion RandomPasswordGeneration
Function Convert-HRBDepartmentNumber {
  param(
   [Parameter(Mandatory=$True,
     Position=0)]
  [string]$DepartmentNumber
  ) # param end

  (($DepartmentNumber.Replace('.','')) -replace '^10','').trim().PadRight(5,'0')
}
Function damChoice {
    [CmdletBinding(
        SupportsShouldProcess=$true 
        )] # CmdletBinding
    Param (
        # ChoiceMessage help description
        [Parameter(
            Mandatory=$true, 
            ValueFromPipeline=$true,
            ValueFromPipelineByPropertyName=$true )]
        [Alias("msg")] 
        $ChoiceMessage
        <#
        # # Param2 help description
        # [Parameter(ParameterSetName='Parameter Set 1')]
        # [AllowNull()]
        # [AllowEmptyCollection()]
        # [AllowEmptyString()]
        # [ValidateScript({$true})]
        # [ValidateRange(0,5)]
        # [int]
        # $Param2,
        #
        # # Param3 help description
        # [Parameter(ParameterSetName='Another Parameter Set')]
        # [ValidatePattern("[a-z]*")]
        # [ValidateLength(0,15)]
        # [String]
        # $Param3 #>

        ) # Param
    Begin {
    } #Begin
    Process {
        Write-host ($ChoiceMessage,"?"," (Y/N) " -join '') -ForegroundColor Yellow -NoNewline
        $Readhost = Read-Host
        Switch ($ReadHost) { 
            Y { 
                Write-verbose $ChoiceMessage
                return $true} 
            N { 
                Write-verbose $ChoiceMessage
                return $false} 
            Default {
                Write-Verbose "Default, Skip PublishSettings"
                return $false} 
            } # Switch ($ReadHost)
        } # Process
    End {
    } # End
} # Function damChoice
Function Get-Clipboard([switch] $Lines) {
    if($Lines) {
        $cmd = {
            Add-Type -Assembly PresentationCore
            [Windows.Clipboard]::GetText() -replace "`r", '' -split "`n"
        }
    } else {
        $cmd = {
            Add-Type -Assembly PresentationCore
            [Windows.Clipboard]::GetText()
        }
    }
    if([threading.thread]::CurrentThread.GetApartmentState() -eq 'MTA') {
        & powershell -Sta -Command $cmd
    } else {
        & $cmd
    }
}
Function Get-Folder {
 [CmdletBinding()]
 param(
    [Parameter(Mandatory=$false,
      Position=0)]
    $InitialDirectory = $(if($PSCommandPath -eq ""){$env:userprofile}else{$((Get-Item $PSCommandPath).DirectoryName)}),
    
    [Parameter(Mandatory=$false,
      Position=1)]
    $Title = $null
  ) # param end
 [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") |  Out-Null
 $FolderBrowserDialog = New-Object System.Windows.Forms.FolderBrowserDialog
 $FolderBrowserDialog.SelectedPath = if ($FolderBrowserDialog.SelectedPath -eq "")
                                      {"\\vab-vfp-01\hrb_updates"}
                                     else
                                      {$FolderBrowserDialog.SelectedPath} # initial/default path
 $FolderBrowserDialog.ShowDialog() | Out-Null
 $FolderBrowserDialog.SelectedPath
} #Function Get-Folder
Function Get-FileName {
<#
.SYNOPSIS
Creates a graphical OpenFileDialog box for file selection.
 
.DESCRIPTION
  Generates a graphical OpenFileDialog box, returns the full pathname of a selected object, or $null if cancelled.
 
.EXAMPLE
Get-Filename
Generates an openFileDialog window in the current folder. Displays all files and folders
 
.EXAMPLE
Get-Filename -filter 'All Files (*.*)|*.*'
  Generates an openFileDialog window in the current folder. Displays all files and folders
 
.EXAMPLE
Get-Filename -filter 'Powershell Files (*.ps*)|*.ps*'
  Generates an openFileDialog window in the current folder. Displays all powershell files.
 
.EXAMPLE
Get-Filename -filter 'Powershell Files (*.ps*)|*.ps*|Excel Files (*.xl*)|*.xlx*'
Generates an openFileDialog window in the current folder. Displays all powershell files.
Dialog includes a file selection filter dropdown with a second entry for Excel files.
 
.PARAMETER initialDirectory
The directory displayed when the dialog starts. The default is the current folder.
 
.PARAMETER Filter
Gets or sets a filter string that specifies the file types and descriptions to display in the OpenFileDialog.
 
If the Filter property is Empty, all files are displayed. Folders are always displayed.
 
Filter consists of a description of the filter followed by a vertical bar (|) and the filter pattern. The filter can specify one or more file types.
 
The description describes the type of files shown in the dialog box. Although the description can be any string, it usually consists of the type of files included in the filter followed by the parentheses that contain the extensions associated with the description. The filter description appears in the drop-down list of the dialog box. The following is an example of a filter description.
 
   My Files (*.my)
 
The filter pattern determines which files are shown by the dialog box. Filter patterns for the same description are separated by a semicolon (;). You can specify an exact match or use the wildcard character (*) in combination with the dot character (.) to specify file name or extension matches.
 
The following is an example of a filter description followed by multiple filter patterns. This example adds Image Files (*.bmp, *.jpg) to the drop-down list and shows .bmp and .jpg files when it is selected.
   Image Files (*.bmp, *.jpg)|*.bmp;*.jpg
 
Multiple filter options are separated by the vertical bar.
 
The following is an example of multiple filter descriptions and patterns. This example adds Text Files (*.txt) and All Files (*.*) to the drop-down list. When Text Files (*.txt) is selected, .txt files are shown. When All Files (*.*) is selected, all file types are shown.
   Text Files (*.txt)|*.txt|All Files (*.*)|*.*
-----------------------------
 
.PARAMETER Title
Sets the default title of the dialog box.
 
#>

 param(
    [Parameter(Mandatory=$false,
      Position=0,
      HelpMessage="Starting directory for Search")]
    $initialDirectory = $(if($PSCommandPath -eq ""){$env:userprofile}else{$((Get-Item $PSCommandPath).DirectoryName)}),
    
    [Parameter(
      HelpMessage="contains at least 2 pipe '|' separated parts i.e.:'CSV files (*.csv)| *.csv'"
      )]
    $Filter = "PowerShell (*.ps*)|*.ps*|CSV files (*.csv)| *.csv|ALL Files (*.*)| *.*",
    
    [Parameter(Mandatory=$false,
      Position=1)]
    $Title = $null
  ) # param end
 [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") |  Out-Null
 $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
 $OpenFileDialog.initialDirectory = $initialDirectory
 $OpenFileDialog.filter = $Filter
 $OpenFileDialog.Title=$Title
 $OpenFileDialog.ShowDialog() | Out-Null
 $OpenFileDialog.filename
} #end function Get-FileName
Function Get-HRBformat {
<#
.SYNOPSIS
  Determines HRB column format, New or Old
 
.DESCRIPTION
  Determines HRB column format, New or Old
 
.PARAMETER csvData
  Mandatory. data set created by the import-csv command
 
.OUTPUTS
  None
 
.NOTES
  Version: 1.0
  Author: Dan Murray
  Creation Date: 11/29/2016
 
.LINK
 
.EXAMPLE
  Get-HRBformat -csvData $importedCSV
 
#>

  [CmdletBinding()]
  Param (
    [Parameter(Mandatory=$true,Position=0)]$csvData
  )

  $oldFields=(
            'City',
            'Date of Birth',
            'Date of hire/rehire',
            'Employee Id',
            'Employee Status Type',
            'First Name',
            'Home Department',
            'Home Department Code',
            'Home email',
            'Home phone',
            'Job code',
            'Job title',
            'Last Name',
            'Location',
            'Manager ID',
            'Middle Name',
            'Mngr. FName',
            'Mngr. LName',
            'Mngr. MName',
            'Original Date of hire',
            'Status Eff. Date',
            # 'TX',
            'Work Email',
            'Work Phone',
            'Zip/Postal Code')
  $oldFmt=$true
  $newFields=(
    'Associate ID',
    'Birth Date',
    'Business Unit Description',
    'File Number',
    'First Name',
    'Hire Date',
    'Home Department Code',
    'Home Department Description',
    'Job Title Code',
    'Job Title Description',
    'Last Name',
    'Location Description',
    'Middle Name',
    'Personal Contact: Home Phone',
    'Personal Contact: Personal Email',
    'Position Status',
    'Primary Address: City',
    'Primary Address: Zip / Postal Code',
    'Rehire Date',
    'Reports To Associate ID',
    'Reports To First Name',
    'Reports To Last Name',
    'Reports To Middle Name',
    'Status Effective Date',
    'Work Contact: Work Email',
    'Work Contact: Work Phone')
  $newFmt=$true

  $csvData|
   Get-Member -MemberType NoteProperty|
   Select-Object name|
   ForEach-Object -Begin {$csvFlds=@()} -Process {$csvFlds+=$_.name}
   Write-host "Checking Old Format"
   (0..([int]($oldfields.count)-1))|%{
    if($oldFmt){
      if($csvFlds -contains $oldfields[$_]) {
      }
      else { write-host "'$($oldFields[$_])' is missing" -ForegroundColor RED
        $oldFmt=$false } } }
   Write-host "Checking New Format"
  (0..([int]($newFields.count)-1))|%{
    if($newFmt){
      if($csvFlds -contains $newFields[$_]) { 
       #write-host $newFields[$_], $newFmt -ForegroundColor Green
       }
      else { write-host "'$($newFields[$_])' is missing" -ForegroundColor RED
        $newFmt=$false }
      }}
  if($newFmt){'New Format'}
  elseif($oldFmt){'Old Format'}
  else{'Unknown Format'}
  } #end Function Get-HRBformat
Function Get-MX ($domain) {
    try{((  Resolve-DnsName -Type MX $domain -ErrorAction Stop ) | 
        where nameexchange -ne $null | 
        sort preference
    ).nameexchange
    #((Resolve-DnsName -Type MX $domain) | where {$_.preference -eq 10}).NameExchange
    }
    catch {$null}
    }
Function Get-ScriptOrCurrentPath {
<#
.NOTES
 Version: 3.0
 Author: DMurray
 Creation Date: 2016JUN15
 Purpose/Change: Initial script development
 
 $tsServer="http://timestamp.comodoca.com/authenticode"
 $mycert=(gci Cert:\CurrentUser\my -CodeSigningCert)[0]
 dir .\*.ps1
 Set-AuthenticodeSignature (read-host "Script? ") -Certificate $mycert -TimestampServer $tsServer
 
.SYNOPSIS
 Returns path of script or function file. If executed from the command line, it will return:
 '\\vab-vfp-01\hrb_updates$'
 
.DESCRIPTION
 Returns path of script or function file. If executed from the command line, it will return:
 '\\vab-vfp-01\hrb_updates$'
 
.PARAMETER Path
 Permits overriding default path
 
#>
 #Comment_based_Help
[CmdletBinding(SupportsShouldProcess=$true)]
param(
  [Parameter(Mandatory=$false,
    Position=0)]
    [string]$Path = "\\vab-vfp-01\hrb_updates$"
) # param end
  
Begin{} #Begin
  
Process{
  write-debug "in try"
  if ($PSScriptRoot -eq $null) {$Path}
  elseif ($PSScriptRoot -eq '') {$Path}
  elseif ($PSScriptRoot -match '\\Windows\\System32') {$Path}
  else {$PSScriptRoot}
} #Process

End{} #End
}
Function Get-ScriptVersion {
<#
  .NOTES
  Version: 1.0
  Author: DMurray
  Creation Date: 2016JUN15
  Purpose/Change: Initial script development
 
  .SYNOPSIS
  Returns last modified date/time of script.
   
  If a script name is not provided, will return the current date/time as a string in the format 'yyyyMMMdd-HHmmss'"
 
  .DESCRIPTION
  Returns last modified date/time of script.
   
  If a script name is not provided, will return the current date/time as a string in the format 'yyyyMMMdd-HHmmss'"
 
#>

  param(
    [Parameter(
      Mandatory=$false,
      HelpMessage="The full name and path of the script. If not provided, will return the current date/time"
     )]
    $ScriptPath
  )

  if (!($ScriptPath))
    {(get-date)}
  else
    {(Get-Item $ScriptPath).lastwritetime.tostring("yyyyMMMdd-HHmmss").ToUpper()}
}
Function MyCmdLets{
$Text        = @"
Function Verb-Noun {
<#
.SYNOPSIS
    A brief description of the function or script. This keyword can be used
    only once in each topic.
 
.DESCRIPTION
    A detailed description of the function or script. This keyword can be
    used only once in each topic.
 
.PARAMETER <Parameter-Name>
    The description of a parameter. Add a .PARAMETER keyword for
    each parameter in the function or script syntax.
 
    Type the parameter name on the same line as the .PARAMETER keyword.
    Type the parameter description on the lines following the .PARAMETER
    keyword. Windows PowerShell interprets all text between the .PARAMETER
    line and the next keyword or the end of the comment block as part of
    the parameter description. The description can include paragraph breaks.
 
    The Parameter keywords can appear in any order in the comment block, but
    the function or script syntax determines the order in which the parameters
    (and their descriptions) appear in help topic. To change the order,
    change the syntax.
  
    You can also specify a parameter description by placing a comment in the
    function or script syntax immediately before the parameter variable name.
    If you use both a syntax comment and a Parameter keyword, the description
    associated with the Parameter keyword is used, and the syntax comment is
    ignored.
 
 
.EXAMPLE
    A sample command that uses the function or script, optionally followed
    by sample output and a description. Repeat this keyword for each example.
 
.INPUTS
    The Microsoft .NET Framework types of objects that can be piped to the
    function or script. You can also include a description of the input
    objects.
 
.OUTPUTS
    The .NET Framework type of the objects that the cmdlet returns. You can
    also include a description of the returned objects.
 
.NOTES
    Additional information about the function or script.
 
.LINK
    The name of a related topic. The value appears on the line below
    the .LINE keyword and must be preceded by a comment symbol (#) or
    included in the comment block.
 
    Repeat the .LINK keyword for each related topic.
 
    This content appears in the Related Links section of the help topic.
 
    The Link keyword content can also include a Uniform Resource Identifier
    (URI) to an online version of the same help topic. The online version
    opens when you use the Online parameter of Get-Help. The URI must begin
    with "http" or "https".
 
.COMPONENT
    The technology or feature that the function or script uses, or to which
    it is related. This content appears when the Get-Help command includes
    the Component parameter of Get-Help.
 
.ROLE
    The user role for the help topic. This content appears when the Get-Help
    command includes the Role parameter of Get-Help.
 
.FUNCTIONALITY
    The intended use of the function. This content appears when the Get-Help
    command includes the Functionality parameter of Get-Help.
 
.FORWARDHELPTARGETNAME <Command-Name>
    Redirects to the help topic for the specified command. You can redirect
    users to any help topic, including help topics for a function, script,
    cmdlet, or provider.
 
.FORWARDHELPCATEGORY <Category>
    Specifies the help category of the item in ForwardHelpTargetName.
    Valid values are Alias, Cmdlet, HelpFile, Function, Provider, General,
    FAQ, Glossary, ScriptCommand, ExternalScript, Filter, or All. Use this
    keyword to avoid conflicts when there are commands with the same name.
 
.REMOTEHELPRUNSPACE <PSSession-variable>
    Specifies a session that contains the help topic. Enter a variable that
    contains a PSSession. This keyword is used by the Export-PSSession
    cmdlet to find the help topics for the exported commands.
 
.EXTERNALHELP <XML Help File>
    Specifies an XML-based help file for the script or function.
 
    The ExternalHelp keyword is required when a function or script
    is documented in XML files. Without this keyword, Get-Help cannot
    find the XML-based help file for the function or script.
 
    The ExternalHelp keyword takes precedence over other comment-based
    help keywords. If ExternalHelp is present, Get-Help does not display
    comment-based help, even if it cannot find a help topic that matches
    the value of the ExternalHelp keyword.
 
    If the function is exported by a module, set the value of the
    ExternalHelp keyword to a file name without a path. Get-Help looks for
    the specified file name in a language-specific subdirectory of the module
    directory. There are no requirements for the name of the XML-based help
    file for a function, but a best practice is to use the following format:
    <ScriptModule.psm1>-help.xml
 
    If the function is not included in a module, include a path to the
    XML-based help file. If the value includes a path and the path contains
    UI-culture-specific subdirectories, Get-Help searches the subdirectories
    recursively for an XML file with the name of the script or function in
    accordance with the language fallback standards established for Windows,
    just as it does in a module directory.
 
    For more information about the cmdlet help XML-based help file format,
    see "How to Create Cmdlet Help" in the MSDN (Microsoft Developer Network)
    library at http://go.microsoft.com/fwlink/?LinkID=123415.
#>
    [CmdletBinding(
        DefaultParameterSetName='Parameter Set 1',
        SupportsShouldProcess=$true,
        PositionalBinding=$false,
        HelpUri = 'http://www.microsoft.com/',
        ConfirmImpact='Medium')]
    [Alias()]
    [OutputType([String])]
    Param ( <#
        # Param1 help description
        [Parameter(
            Mandatory=$true,
            ValueFromPipeline=$true,
            ValueFromPipelineByPropertyName=$true,
            ValueFromRemainingArguments=$false,
            Position=0,
            ParameterSetName='Parameter Set 1')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [ValidateCount(0,5)]
        [ValidateSet("sun", "moon", "earth")]
        [Alias("p1")]
        $Param1,
 
        # Param2 help description
        [Parameter(
            ParameterSetName='Parameter Set 1')]
        [AllowNull()]
        [AllowEmptyCollection()]
        [AllowEmptyString()]
        [ValidateScript({$true})]
        [ValidateRange(0,5)]
        [int]
        $Param2,
 
        # Param3 help description
        [Parameter(
            ParameterSetName='Another Parameter Set')]
        [ValidatePattern("[a-z]*")]
        [ValidateLength(0,15)]
        [String]
        $Param3
        #>
    )
 
    Begin {
    } #Begin
    Process {
        if ($pscmdlet.ShouldProcess("Target", "Operation")){
        } # if ($pscmdlet.ShouldProcess
    } #Process
    End {
    } #End
}
"@

$Title       = " DM Function Template"
$Description = "My Tweak on Built-In 'Cmdlet (advanced function) - complete' template"
$Author      = "Dan Murray"
if (-not(Get-IseSnippet | where name -Like $Title*)){
    New-ISESnippet –Text $Text –Title $Title –Description $Description –Author $Author}
else {write-host $Title -fore Green}
} # Function MyCmdLets
Function New-FileSystemWatcher  {
<#
.DESCRIPTION
Monitors changes to a folder.
This uses a FileSystemWatcher object and its WaitForChanged method, which is rather nifty way to not use much resource to keep track of file system changes. What we’re NOT doing here is polling the folder contents.
 
.LINK
https://rcmtech.wordpress.com/2015/07/23/powershell-monitor-changes-to-a-folder/
#>

[cmdletbinding(SupportsShouldProcess=$true)]
Param (
  [parameter()]
  [string]$Path,
  
  [parameter()]
  [ValidateSet('Changed','Created','Deleted','Renamed')]
  [string[]]$EventName,
  
  [parameter()]
  [string]$Filter,
  
  [parameter()]
  [System.IO.NotifyFilters]$NotifyFilter,
  
  [parameter()]
  [switch]$Recurse,
  
  [parameter()]
  [scriptblock]$Action
  )

#region Build FileSystemWatcher
$FileSystemWatcher  = New-Object  System.IO.FileSystemWatcher
If (-NOT $PSBoundParameters.ContainsKey('Path')){
  $Path  = $PWD
  } #If (-NOT $PSBoundParameters.ContainsKey('Path'))

$FileSystemWatcher.Path = $Path
If ($PSBoundParameters.ContainsKey('Filter')) {
  $FileSystemWatcher.Filter = $Filter
  } #If ($PSBoundParameters.ContainsKey('Filter'))

If ($PSBoundParameters.ContainsKey('NotifyFilter')) {
  $FileSystemWatcher.NotifyFilter =  $NotifyFilter
  } #If ($PSBoundParameters.ContainsKey('NotifyFilter'))

If ($PSBoundParameters.ContainsKey('Recurse')) {
  $FileSystemWatcher.IncludeSubdirectories =  $True
  } #If ($PSBoundParameters.ContainsKey('Recurse'))

If (-NOT $PSBoundParameters.ContainsKey('EventName')){
  $EventName  = 'Changed','Created','Deleted','Renamed'
  } #If (-NOT $PSBoundParameters.ContainsKey('EventName'))

If (-NOT $PSBoundParameters.ContainsKey('Action')){
  $Action  = {
  Switch  ($Event.SourceEventArgs.ChangeType) {
    'Renamed'  {
      $Object  = "{0} was {1} to {2} at {3}" -f $Event.SourceArgs[-1].OldFullPath,
      $Event.SourceEventArgs.ChangeType,
      $Event.SourceArgs[-1].FullPath,
      $Event.TimeGenerated
      } #'Renamed'
    Default  {
      $Object  = "{0} was {1} at {2}" -f $Event.SourceEventArgs.FullPath,
      $Event.SourceEventArgs.ChangeType,
      $Event.TimeGenerated
      } #Default
    } #Switch ($Event.SourceEventArgs.ChangeType)

$WriteHostParams  = @{
  ForegroundColor = 'Green'
  BackgroundColor = 'Black'
  Object =  $Object
  } #$WriteHostParams
Write-Host  @WriteHostParams
} #$Action
  } #If (-NOT $PSBoundParameters.ContainsKey('Action'))

#endregion Build FileSystemWatcher

#region Initiate Jobs for FileSystemWatcher

$ObjectEventParams  = @{
  InputObject =  $FileSystemWatcher
  Action =  $Action
  } #$ObjectEventParams

ForEach  ($Item in  $EventName) {
  $ObjectEventParams.EventName = $Item
  $ObjectEventParams.SourceIdentifier =  "File.$($Item)"
  Write-Verbose  "Starting watcher for Event: $($Item)"
  $Null  = Register-ObjectEvent  @ObjectEventParams
  } #ForEach ($Item in $EventName)

#endregion Initiate Jobs for FileSystemWatcher

} 
Function New-LogFileName() {
  param(
  [Parameter(
    Mandatory=$false,
    HelpMessage="The Base Name of the log file. Needs to include the path. If running interactively, will return 'Console'"
   )]
  $BaseName,
  [Parameter(
    Mandatory=$false,
    HelpMessage="The suffix of the log file name. Default is 'run.log'"
   )]
  $Suffix='Run.log',
  [Parameter(
    Mandatory=$false,
    HelpMessage='Appends a timestamp to the base filename if $true.'
   )]
  $TimeStamp=$false
  )

  if (!($BaseName))
    { if(!($MyInvocation.MyCommand.Path))
      {"$($env:TMP)`\Console",[string](get-random),$suffix -join '-'}
      else
      { if($TimeStamp)
        {(get-item($MyInvocation.MyCommand.Path)).BaseName,$((Get-date).toString("yyyMMMdd-HHmm").toupper()),[string](get-random),$suffix -join '-'}
        else
        {(get-item($MyInvocation.MyCommand.Path)).BaseName,[string](get-random),$suffix -join '-'} }
    } # if (!($BaseName))
  else #else if (!($BaseName))
    { if($TimeStamp)
      {$BaseName,$((Get-date).toString("yyyMMMdd-HHmm").toupper()),[string](get-random),$Suffix -join '-' }
      else
      {$BaseName,[string](get-random),$Suffix -join '-' }
    } #else if (!($BaseName))
}
Function New-UniqueSAMName {
<#
.NOTES
 Version: 1.0
 Author: DMurray
 Creation Date: 2016APR14
 Purpose/Change: Initial script development
 
.SYNOPSIS
 Generate a unique SAMAccountName
 
.DESCRIPTION
 Generates a unique SAMAccountName
 Uses First Initial, Last Name. If not unique, add additional letters of First Name.
 If still not unique, insert Middle Initial (if one is present).
 Finally, if STILL not unique, use format FirstMLast## (where ## is a 2-digit incrementing sequence number)
 FLast? -> FiLast? -> FirLast? -> FirsLast? -> FirstLast? -> FirstMLast? -> FirstMLast##
  
 Empl# Legal Name SAMAccountName
 1 Sam Jackson SJackson
 2 Sam Jackson SaJackson
 3 Sam Jackson SamJackson
 4 Sam Jackson SamJackson01
 5 Sam Jackson SamJackson02
 6 Samuel Jackson SamuJackson
 
.PARAMETER GivenName
 First Name
 
.PARAMETER Surname
 Last Name
 
.PARAMETER MI
 Middle Initial
 
#>
 #Comment_based_Help

[cmdletbinding(SupportsShouldProcess=$true)]

Param(
  [parameter(Mandatory=$true,
    HelpMessage="New Users' Last Name. This item is MANDATORY.")]
  [Alias('Last','LastName','Last Name','SurName')] 
  [String]$LName,

  [parameter(Mandatory=$true,
    HelpMessage="New Users' First Name. This item is MANDATORY.")]
  [Alias('First','FirstName','First Name','GivenName')] 
  [String]$FName,

  [parameter(Mandatory=$false,
    HelpMessage="New Users' Middle Name or Initial. This item is OPTIONAL.")]
  [Alias('Middle','MiddleName','MName')] 
  [String]$MI=""
)

$bUnique=$false
$LName=($LName|%{($_-split " ")|%{($_.substring(0,1).toupper()+$_.substring(1).tolower()).replace(" ","").replace(".","").replace(",","") } }) -join ""
$fnLen=$FName.Length
$lnLen=$LName.Length
while (-not $bUnique){
  #"In outer while"
  1..$FName.Length| %{
    #Write-host "$_. Testing " -NoNewline
    $uSAMName=$FName.Substring(0,$_)+$LName
    #Write-host $tstName
    [string[]]$tusrs=(get-aduser -filter {samaccountname -eq $uSAMName} -Properties *)
    if($tusrs.Count -eq 0) {
      rv tusrs
      $bunique=$true
      break} #if($tusrs.Count -eq 0)
  } #1..$GivenName.Length

  #test again; inserting Middle Initial
  $uSAMName=$FName+$($mi.Trim())+$LName
  [string[]]$tusrs=(get-aduser -filter {samaccountname -eq $uSAMName} -Properties *)
  if($tusrs.Count -eq 0) {
    rv tusrs
    $bunique=$true
    break} #if($tusrs.Count -eq 0)
  
  #Still Here? Start adding numbers 01-99
  1..99|%{
    [string[]]$tusrs=(get-aduser -filter {samaccountname -eq "$tname$($_.tostring('00'))"} -Properties *)
    if($tusrs.Count -eq 0) {
      $uSAMName="$uSAMName$($_.tostring('00'))"
      rv tusrs
      $bunique=$true
      break} #if($tusrs.Count -eq 0)
  } # 1..99

} #while (-not $bUnique)
#($tstName|%{($_-split " ")|%{($_.substring(0,1).toupper()+$_.substring(1).tolower()).replace(" ","").replace(".","").replace(",","") } }) -join ""
$uSAMName
}
Function Notify-ExpiringAccounts {
    [CmdletBinding(SupportsShouldProcess=$true)]
    Param (
        $MaxPwdAge = 
            (Get-ADDefaultDomainPasswordPolicy).MaxPasswordage.Days,
        $DaysToExpire = 
            14
        )
    Begin {
        Write-Verbose "Beginning..."        
        #region SUPPORTING_FUNCTIONS
        Function writeHtmlFooter {
        [cmdletbinding(SupportsShouldProcess=$true)]
        param($fileName)
        Add-Content $fileName "</body>"
        Add-Content $fileName "</html>"
        } # Function to write the HTML Footer to the file
        #endregion SUPPORTING_FUNCTIONS
        #region VARIABLES
        $AccountNoExpire = 
            9223372036854775807 #Value when the account expiration date is blank
        $DomainDN = 
            (Get-ADDomain).distinguishedName
        $LogFile = 
            New-LogFileName
        $ScriptVersion =
            (Get-ScriptVersion).tostring("ddMMMyyyyHHmmss").toupper()
        $ExpiringUserBody = 
            @()
        $ExpiringAccountBody = 
            @()
        $dUsers= (get-aduser -Properties *  -Filter { 
                (enabled -eq $true) } -SearchBase "ou=users,ou=mckean,dc=mckean,dc=local" )| 
            select *,
            @{l="Expires"  ;E={ $MaxPwdAge - ((Get-Date) - $_.PasswordLastSet).days }},
            @{L="LastSeen" ;e={((get-date)-$_.lastlogondate).days}}, #Days Since Last Logon
            @{L="ExpiresIn";E={ ($_.AccountExpirationDate - (get-date)).days }},
            @{L="MgrEmail" ;e={((get-aduser (Get-ADUser $_.samaccountname -Properties *).manager -properties mail).mail)}},
            @{L="MgrGiven" ;e={((get-aduser (Get-ADUser $_.samaccountname -Properties *).manager).givenName)}}

        Write-Verbose "Locating Expiring accounts..."
        $ExpiringAccounts = $dUsers | where {
                ($_.enabled -eq $true) -and 
                ($_.accountexpires -ne $AccountNoExpire) -and 
                ($_.accountexpires -ne 0) } | 
            Where {$_.ExpiresIn -le $DaysToExpire } 
        
        $ExpiringAccounts|sort expires -Descending|ft name,samaccountname,expiresIn,AccountExpirationDate,EmployeeNumber,MgrGiven,MgrEmail -AutoSize

        Write-Verbose "Locating accounts with passwords expiring in the next $MaxPwdAge days..."
        $ExpiringPasswords = $dUsers | 
            Where-Object {$_.Expires -gt 0 -AND $_.Expires -le $DaysToExpire } 

        $ExpiringPasswords|sort expires -Descending|ft name,samaccountname,expires,passwordlastset,EmployeeNumber,MgrEmail -AutoSize
                
        #endregion VARIABLES

        Write-Verbose "Domain 'MaximumPasswordAge' is $($MaxPwdAge) days."
        Write-Verbose "Found $($ExpiringPasswords.count) accounts with passwords expiring within $($DaysToExpire) days"
        Write-Verbose "Found $($ExpiringAccounts.count) accounts set to expire soon."
        
        #"McKean-alerts@mckean-defense.com"
    } # Begin
    Process {
        #region ExpiringPasswords
        foreach($Acct in $ExpiringPasswords) {
            $mailSplat = @{}
            $mailSplat.From = 
                "McKean HelpDesk <helpdesk@mckean-defense.com>"
            $mailSplat.BCC = 
                #"McKean HelpDesk <helpdesk@mckean-defense.com>",
                #"Dan Murray <dmurray@mckean-defense.com>",
                "Dan Murray <dmurray@murdan.net>"
            $mailSplat.SmtpServer = 
                "smtp.mckean.local"
            $mailsplat.Cc = "McKean-alerts@mckean-defense.com"
            $mailSplat.to = #"Dan Murray <dmurray@murdan.net>"
                &{
                if($Acct.expires -le 7){
                    ($Acct.mail,$Acct.MgrEmail)} 
                else {
                    ($Acct.mail)}}
                # $Acct.mail #>
            $mailSplat.subject = 
                "Reminder: Your '$($Acct.UserPrincipalName)' password will expire in $($Acct.Expires) days."
            $mailSplat.body = (
                $acct.givenName,
                "Your $($Acct.UserPrincipalName) password will expire in $($Acct.Expires) days. " ,
                "===============================================",
                "This is an automated notification. DO NOT REPLY. ",
                "Should you have questions, please send a message, with contact information to: ",
                " helpdesk@mckean-defense.com. ",
                "===============================================",
                "",
                "If you are using a McKean issued Windows machine AND you are physically in the Crane, San Diego, Philadelphia, DC, or Va Beach McKean Office,you can update your password by pressing CTRL-ALT-DEL and choosing 'Change a Password'. ",
                "",
                "===============================================",
                "NOTE: When you update your password using the password reset website at https://reset.mckean-defense.com, your physical computer will remain unaware of the network password change until it reconnects to the McKean LAN at one of the sites listed above. Until that time, you will need to continue to log in to your local machine with your current password, but remember that mSync and eMail will be IMMEDIATELY aware of the change.",
                "===============================================",
                "NOTE: This will also updates the password used to access mSync, and Company eMail. ",
                "===============================================",
                "ALERT: Make certain you update any saved passwords, especially on mobile devices such as iPads, Droids, iPhones, etc. Failure to do so WILL lockout your account as these devices attempt to login with expired (invalid) passwords. ",
                " ",
                "NOTE: When Outlook prompts you for your new password, don't forget that your USERNAME ends with '@mckean.LOCAL', NOT '@mckean-defense.com' ",
                " ",
                "Script Version: $ScriptVersion " | out-string )
            Send-MailMessage @mailSplat

        }
        #endregion ExpiringAccounts

        #region ExpiringAccounts
        foreach($Acct in $ExpiringAccounts) {
            $mailSplat = @{}
            $mailSplat.subject = 
                "Reminder: The account for '$($Acct.name)' will expire on $($Acct.AccountExpirationDate.tostring("dd MMM yyyy"))."
            $mailSplat.From = 
                "McKean HelpDesk <helpdesk@mckean-defense.com>"
            $mailSplat.BCC = 
                "Dan Murray <dmurray@mckean-defense.com>"#,
                #"Dan Murray <dmurray@murdan.net>"
            $mailSplat.SmtpServer = 
                "smtp.mckean.local"
            $mailSplat.to = $Acct.MgrEmail #"Dan Murray <dmurray@murdan.net>"
            $mailsplat.Cc = "McKean-alerts@mckean-defense.com"
            $mailSplat.body = 
                ($acct.givenName,
                "===============================================",
                "This is an automated notification. DO NOT REPLY. ",
                "Should you have questions, please send a message, with contact information to: ",
                " helpdesk@mckean-defense.com. ",
                "===============================================",
                " ",
                "The account for '$($Acct.displayname)' expires in $($acct.ExpiresIn) days on $($Acct.AccountExpirationDate.tostring("dd MMM yyyy")).",
                " ",
                "If this account is still required, please open a trouble ticket requesting the expiration date be extended. ",
                " ",
                "===============================================",
                "REMEMBER: ",
                "Non-employee accounts can only be authorized by a McKean employee for a maximum of 90 days at a time.",
                "===============================================",
                " ",
                "Script Version: $ScriptVersion " | out-string)
            Send-MailMessage @mailSplat
        }
        #endregion ExpiringAccounts

    } # Process
    End     {
    } # End
}
#Notify-ExpiringAccounts -Verbose
Function Remove-WindowsOld {
<#
.SYNOPSIS
   Remove-WindowsOld
.DESCRIPTION
   Removes the Windows.Old folder from upgraded machines.
.NOTES
   Source Information: https://regularitguy.com/2013/12/16/how-to-delete-windows-old-from-windows-server-2012-r2/
.EXAMPLE
   Example of how to use this cmdlet
.EXAMPLE
   Another example of how to use this cmdlet
#>

    [cmdletbinding(SupportsShouldProcess=$true)]
    Param (
        # # Param1 help description
        # [Parameter(Mandatory=$true,
        # ValueFromPipelineByPropertyName=$true,
        # Position=0)]
        # $Param1,
        #
        # # Param2 help description
        # [int]
        # $Param2
    ) #Param

    Begin {
        $JunctionSource = 'https://download.sysinternals.com/files/Junction.zip'
        # requires Junction.exe from SysInternals


        #if its not on the system, go get it from MS.
        $junction = &{
            begin{write-host "Looking for 'Junction.exe'"}
            Process {$j=Get-ChildItem c:\junction.exe -Recurse -ErrorAction SilentlyContinue -Verbose}
            end{write-host 'Done!'
                return $j}
            }
        if (!($junction)) {
            invoke-webrequest -uri $JunctionSource -OutFile $( $env:TEMP,(split-path $JunctionSource -Leaf) -join '\')
            $junction = $( $env:TEMP,(split-path $JunctionSource -Leaf) -join '\')
            Expand-Archive -LiteralPath (get-item $junction).FullName -DestinationPath (get-item $junction).Directory -Force
            $junction=Get-ChildItem ($env:TEMP,"junction.exe" -join '\') -Recurse -ErrorAction SilentlyContinue -Verbose

        } #if

        $junction = (Get-Item $junction).FullName

        #Junction List File
        $JunctionList = (Get-Item $junction).fullname -replace 'exe','txt'

    } # Begin
    
    Process {
        # Create a reference file that lists all the junction points and
        # symbolic links in use by opening up a command prompt, changing
        # into C:source and running

        #clear screen
        $myargs = @(
            "-nobanner",
            "-accepteula",
            "-s",
            "-q",
            "c:\windows.old")
        cmd /c $junction $myargs > $junctionList
        #gc $junctionList

        # open up PowerShell ISE administrator rights and run the following
        # to remove all symbolic links and junction points in c:windows.old

        #region RemoveAllSymbolicLinksAndJunctions
        foreach ($line in [System.IO.File]::ReadLines($junctionList))
        { 
            if ($line -match “^\\”)
            {
            $file = $line -replace “(: JUNCTION)|(: SYMBOLIC LINK)”,””
            & $junction -d “$file”
            }
        } # foreach
        #endregion RemoveAllSymbolicLinksAndJunctions

        # take ownership, grant rights and delete windows.old to recover space
        if (test-path c:\windows.old) {
            takeown /F C:windows.old /R /D Y
            remove-item 'c:\windows.old' -Recurse -Force
            }

    } # Process
    
    End {
    } # End
} # Function Remove-WindowsOld
Function Send-PasswordExpirationNotices {

[cmdletbinding(SupportsShouldProcess=$true)]
Param
    (
        [Parameter(
            #Mandatory=$true,
            ValueFromPipelineByPropertyName=$true)]
        [switch]$TestOnly
    )

begin
    { # begin

    $AccountNoExpire=9223372036854775807

    $BodyFileName = $home,"$(get-random).html" -join '\'
    $EmailTo      = "dmurray@mckean-defense.com"
    $EmailFrom    = "noreply@mckean.local"
    $date         = ( get-date ).ToString('MM/dd/yyyy')
    $EmailSubject = "Expiring Users " + $date
    $SMTPServer   = "smtp.mckean.local"
    $ExpiredBody  = {@"
<!DOCTYPE html>
<html>
<head><style>
    body{font-family:courier;}
</style></head><body>
<p>The Active Directory account for $($u.name) was disabled because it expired on $(($u.AccountExpirationDate).tostring("MMM dd,yyyy")).<p>
   
<p>If this individual still:
<ul>
     <li>is ACTIVELY working for McKean, and </li>
     <li>requires access to McKean eMail, mSync and Network resources;</li>
</ul>
      
please reply to this ticket.</p>
<p>If the individual is a contractor or otherwise not a regular, full-time
employee of McKean Defense, the account lifetime is limited to 60 days.</p>
<p>This account may be extended until $( (get-date).AddDays(90).tostring("MMM dd,yyyy") ).</p>
 
<p>Contractor and non-McKean personnel access to McKean IT assets can only be granted in ninety (90) day increments.</p>
 
<p>Failure to reply to this email will result in the account being disabled on <strong>$(($u.AccountExpirationDate).tostring("MMM dd,yyyy"))</strong></p>
 
<p>Thanks for your attention to this matter,
<strong>Network Operations<strong></p>
 
</body></html>
"@
}
    $ExpiringBody = {@"
<!DOCTYPE html>
<html>
<head><style>
    body{font-family:courier;}
</style></head><body>
<p>The Active Directory account for $($u.name) will be expiring in <strong>$($daysLeft)</strong> days [$(($u.AccountExpirationDate).tostring("MMM dd,yyyy"))].<p>
   
<p>If this individual still:
<ul>
     <li>is ACTIVELY working for McKean, and </li>
     <li>requires access to McKean eMail, mSync and Network resources;</li>
</ul>
      
please reply to this ticket.</p>
<p>If the individual is a contractor or otherwise not a regular, full-time
employee of McKean Defense, the account lifetime is limited to 90 days.</p>
<p>This account may be extended until $( (get-date).AddDays(90).tostring("MMM dd,yyyy") ).</p>
 
<p>Contractor and non-McKean personnel access to McKean IT assets can only be granted in ninety (90) day increments.</p>
 
<p>Failure to reply to this email will result in the account being disabled on <strong>$(($u.AccountExpirationDate).tostring("MMM dd,yyyy"))</strong></p>
 
<p>Thanks for your attention to this matter,
<strong>Network Operations<strong></p>
 
</body></html>
"@
}


    
    # Create output file and nullify display output
    New-Item -ItemType file $BodyFileName -Force > $null

    $ReportTitle  = 'Test Report'

    #region ReportHeader
        Add-Content $BodyFileName '<html>'
        Add-Content $BodyFileName '<head>'
        Add-Content $BodyFileName "<meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1'>"
        Add-Content $BodyFileName ('<title>',$ReportTitle,'</title>' -join '')
        Add-Content $BodyFileName '<style>'
        Add-Content $BodyFileName 'body{'
        Add-Content $BodyFileName 'font-family:courier;'
        Add-Content $BodyFileName '}'
        Add-Content $BodyFileName 'table, th, td {'
        Add-Content $BodyFileName ' border: 1px solid black;'
        Add-Content $BodyFileName ' border-collapse: collapse;'
        Add-Content $BodyFileName '}'
        Add-Content $BodyFileName 'th, td {'
        Add-Content $BodyFileName ' padding: 5px;'
        Add-Content $BodyFileName '}'
        Add-Content $BodyFileName '</head>'
        Add-Content $BodyFileName '<body>'
    #endregion ReportHeader

    } # begin

process
    {
    $ExpiringUsers=(get-aduser -Properties *  -Filter { (enabled -eq $true) -and (accountexpires -ne $AccountNoExpire)  -and (accountexpires -ne 0) })
    if (!($ExpiringUsers)) #Nothing to process
        {
        Add-Content $BodyFileName '<p style="font-size:160%">'
        Add-Content $BodyFileName '<b>Nothing to process</b>'
        Add-Content $BodyFileName '</p>'

        Add-Content $BodyFileName '<p style="font-size:160%;color:green;">'
        Add-Content $BodyFileName $date
        Add-Content $BodyFileName '</p>'
        } #Nothing to process
    
    else # process matching accounts
        { # process matching accounts
        #region TableSetup
        Add-Content $BodyFileName '<table>'
        Add-Content $BodyFileName '<tr>'
        Add-Content $BodyFileName '<th>Days Left</th>'
        Add-Content $BodyFileName '<th>User</th>'
        Add-Content $BodyFileName '<th>Account</th>'
        Add-Content $BodyFileName '<th>Manager</th>'
        Add-Content $BodyFileName '<th>Manager''s eMail</th>'
        Add-Content $BodyFileName '</tr>'
        #endregion TableSetup

        foreach ($u in $ExpiringUsers)
            { #foreach ($u in $ExpiringUsers)
            Add-Content $BodyFileName '<tr>'
            $Mgr = (get-aduser -Identity $u.Manager -Properties *)
                        
            switch((($u.AccountExpirationDate - (get-date)).days)) 
            { # switch((($u.AccountExpirationDate - (get-date)).days))
                {$_ -le 0} #already Expired
                    {
                        $daysLeft = $_
                        Add-Content $BodyFileName ('<td style="color:red;"><b>',$daysLeft ,'</td>' -join '')
                        Add-Content $BodyFileName ('<td style="color:red;"><b>',$u.name,'</td>' -join '')
                        Add-Content $BodyFileName ('<td style="color:red;"><b>',$u.samaccountname,'</td>' -join '')
                        Add-Content $BodyFileName ('<td style="color:red;"><b>',(get-aduser -Identity $u.manager -Properties *).name,'</td>' -join '')
                        Add-Content $BodyFileName ('<td style="color:red;"><b>',(get-aduser -Identity $u.manager -Properties *).mail,'</td>' -join '')
                
                        #DISABLE EXPIRED USER ACCOUNT
                            $u.Enabled = $false
                            set-aduser -Instance $u

                        # notify manager
                        $mailto = if($testOnly)
                                    {'Dan Murray <dmurray@mckean-defense.com>'}
                                else
                                    {
                                    @("$($mgr.givenname) $($mgr.surname) <$($mgr.mail)>")
                                    }
                        Write-Debug $testonly
                        Write-Verbose $mailto
                        Send-MailMessage `
                            -To        $mailto
                            -bcc       'Dan Murray <dmurray@mckean-defense.com>'  `
                            -Subject   ('Expiring Employee Account:',$u.samaccountname,'Disabled' -join ' ') `
                            -From         $EmailFrom `
                            -SmtpServer $SMTPServer `
                            -bodyashtml             `
                            -Body       $(&$ExpiredBody)

                        break
                    } #switch {$_ -le 0} #already Expired

                {$_ -lt 14} #expiring w/in 14 days
                    {
                        $daysLeft = $_
                        Add-Content $BodyFileName ('<td>',$daysLeft ,'</td>' -join '')
                        Add-Content $BodyFileName ('<td>',$u.name,'</td>' -join '')
                        Add-Content $BodyFileName ('<td>',$u.samaccountname,'</td>' -join '')
                        Add-Content $BodyFileName ('<td>',(get-aduser -Identity $u.manager -properties *).name,'</td>' -join '')
                        Add-Content $BodyFileName ('<td>',(get-aduser -Identity $u.manager -properties *).mail,'</td>' -join '')
                        
                        ## notify manager and user
                        $mailto = if($testOnly)
                                    {'Dan Murray <dmurray@mckean-defense.com>'}
                                else
                                    {
                                    @("$($u.givenname) $($u.surname) <$($u.mail)>",
                                      "$($mgr.givenname) $($mgr.surname) <$($mgr.mail)>")
                                    }
                        Write-Debug $testonly
                        Write-Verbose $mailto

                        Send-MailMessage `
                            -To        $mailto
                            -bcc       'Dan Murray <dmurray@mckean-defense.com>'  `
                            -Subject   ('Expiring Employee Account:',$u.samaccountname,'Disabled' -join ' ') `
                            -From         $EmailFrom `
                            -SmtpServer $SMTPServer `
                            -bodyashtml             `
                            -Body       $(&$ExpiringBody)


                        break

                    } #switch {$_ -lt 14} #expiring w/in 14 days

                default #expiring, but not within 14 days, and not already expired
                    {
                        Add-Content $BodyFileName ('<td>',$_ ,'</td>' -join '')
                        Add-Content $BodyFileName ('<td>',$u.name,'</td>' -join '')
                        Add-Content $BodyFileName ('<td>',$u.samaccountname,'</td>' -join '')
                        Add-Content $BodyFileName ('<td>',(get-aduser -Identity $u.manager -properties *).name,'</td>' -join '')
                        Add-Content $BodyFileName ('<td>',(get-aduser -Identity $u.manager -properties *).mail,'</td>' -join '')

                        break
                    } #switch default #expiring, but not within 14 days, and not already expired
            } # switch((($u.AccountExpirationDate - (get-date)).days))

            Add-Content $BodyFileName '</tr>'
            } #foreach ($u in $ExpiringUsers)
        
        Add-Content $BodyFileName '</table>'
        } # process matching accounts

    } # process

end
    {
    #Clean up the HTML
    Add-Content $BodyFileName "</body>"
    Add-Content $BodyFileName "</html>"

    #Send summary Email
    # $BodyReport = Get-Content "$BodyFileName" -Raw
    Send-MailMessage    `
        -To         $EmailTo `
        -Subject     $EmailSubject `
        -From         $EmailFrom `
        -SmtpServer $SMTPServer `
        -Body       (Get-Content "$BodyFileName" -Raw) `
        -BodyAsHtml    

    (Get-Content "$BodyFileName" -Raw)
    } # end
} #Function Send-PasswordExpirationNotices
Function Sign-Me {
    [CmdletBinding(
        SupportsShouldProcess)]
    Param (
        [Parameter(ValueFromPipeline=$true)]
        $file
    )
    Begin     {
        }
    Process {
        Write-Verbose 'process'
        $tsServer =  "http://timestamp.comodoca.com/authenticode"
        $mycert   =  (gci Cert:\CurrentUser\my -CodeSigningCert) |
                     Where {($_.NotAfter -ge (Get-Date))}
        if(!($file)) {
            Write-Verbose (Get-PSCallStack)[0].Location
            if ((Get-PSCallStack)[0].Location -eq '<no file>'){Write-Verbose (get-location)}
            $file     =  (
                Get-FileName -initialDirectory $(get-location) `
                    -title "Select Script to Sign" `
                    -Filter 'All Files (*.*)|*.*|PowerShell Files (*.ps*)|*.ps*' )
            }
        Write-Verbose (('',
            "Selected File: $file",
            " Certificate: $($mycert.FriendlyName)",
            " Valid until: $($mycert.NotAfter)",
            " Issued By: $($mycert.PSChildName)") | Out-String)
        try   { 
            if($mycert -and $file ){
                Set-AuthenticodeSignature $file -Certificate $mycert -TimestampServer $tsServer
                } # if($mycert -and $file )
            else {
                Write-Verbose 'No certificate or nothing to sign'} # else
            } #try
        catch { Write-Verbose 'Failed to Sign'} # catch
        }
    End {
        # Write-Verbose 'end'}
} 
} # Function SignMe
Function Test-ADCredentials {
<#
.NOTES
 Author: DMurray
 
.SYNOPSIS
 Test AD Credentials
 
.DESCRIPTION
 Tests AD Credentials
 
.PARAMETER username
 username
 
.PARAMETER password
 password
 
.PARAMETER domain
 domain
 
#>
 #Comment_based_Help

  Param($username, $password, $domain)
  Add-Type -AssemblyName System.DirectoryServices.AccountManagement
  $ct = [System.DirectoryServices.AccountManagement.ContextType]::Domain
  $pc = New-Object System.DirectoryServices.AccountManagement.PrincipalContext($ct, $domain)
  New-Object PSObject -Property @{
    UserName = $username;
    IsValid = $pc.ValidateCredentials($username, $password).ToString()
  }
} # Function Test-ADCredentials
Function Test-Callstack {
    Function parent {child} # Function parent
    Function child {
        $callStack = Get-PSCallStack
        if ($callStack.Count -gt 1) {
            'Parent'
            ' FunctionName: {0}' -f $callStack[1].FunctionName
            ' ScriptName: {0}' -f $callStack[1].ScriptName
            ' ScriptName Is Null: {0}' -f ($callStack[1].ScriptName -eq $null)
            if ($callStack[1].ScriptName -ne $null) {
            ' Script File: {0}' -f (get-item $callStack[1].ScriptName).name
            ' Script VersionInfo: {0}' -f (get-item $callStack[1].ScriptName).VersionInfo
            ' Script LastWriteTime: {0}' -f (get-item $callStack[1].ScriptName).LastWriteTime.ToString('yyyyMMdd.HHmmss')
            }
            ' Command: {0}' -f $callStack[1].Command
            ' Location Is Null? {0}' -f ($callStack[1].Location -eq $null)
            ' Location Is Blank? {0}' -f ($callStack[1].Location -eq '')
            ' Location: {0}' -f $callStack[1].Location

            'Child'
            ' FunctionName: {0}' -f $callStack[0].FunctionName
            ' ScriptName: {0}' -f $callStack[0].ScriptName
            if ($callStack[1].ScriptName -ne $null) {
            ' Script File: {0}' -f (get-item $callStack[0].ScriptName).name
            ' Script VersionInfo: {0}' -f (get-item $callStack[0].ScriptName).VersionInfo
            ' Script LastWriteTime: {0}' -f (get-item $callStack[0].ScriptName).LastWriteTime.ToString('yyyyMMdd.HHmmss')
            }
            ' Command: {0}' -f $callStack[0].Command
            ' Location Is Null? {0}' -f ($callStack[0].Location -eq $null)
            ' Location Is Blank? {0}' -f ($callStack[0].Location -eq '')
            ' Location: {0}' -f $callStack[0].Location

            #$callStack[0]|gm
    } # Function child
}
'== Calling Parent ==============='
parent
'== Calling Child ==============='
child
} # Function Test-Callstack
Function Test-NestedFunction {
    [cmdletbinding(SupportsShouldProcess=$true)]
    Param (
        # Param1 help description
        $Param1,

        # Param2 help description
        $Param2
    ) # Param

    Begin {
    
    Function InnerFunction1 {
        [cmdletbinding(SupportsShouldProcess=$true)]
        Param (
            # Param1 help description
            $Param1,

            # Param2 help description
            $Param2
            ) # Param

        Begin {
            Write-Verbose (Get-PSCallStack)[0].functionname
            } # Begin
    
        Process {
            Write-Verbose (Get-PSCallStack)[0].functionname
            } # Process

        End {
            Write-Verbose (Get-PSCallStack)[0].functionname
            } # End
    } # Function InnerFunction1

    Function InnerFunction2 {
        [cmdletbinding(SupportsShouldProcess=$true)]
        Param (
            # Param1 help description
            $Param1,

            # Param2 help description
            $Param2
            ) # Param

        Begin {
            Write-Verbose (Get-PSCallStack)[0].functionname
            } # Begin
    
        Process {
            Write-Verbose (Get-PSCallStack)[0].functionname
            } # Process

        End {
            Write-Verbose (Get-PSCallStack)[0].functionname
            } # End
    } # Function InnerFunction2

    $gpsc=(Get-PSCallStack)[0]
    $gpsc
    Write-Verbose $gpsc.functionname
    Write-Verbose (( ($gpsc.Location) -split ': ')[1]).trim()
    } # Begin
    
    Process {
    Write-Verbose (Get-PSCallStack)[0].functionname
    InnerFunction1
    InnerFunction2
    } # Process

    End {
    Write-Verbose (Get-PSCallStack)[0].functionname
    } # End
} # Function Test-NestedFunction
Function Update-McKeanManagersSharePointGroups {
<#
.NOTES
 Author: DMurray
 
.SYNOPSIS
 Update McKean Managers SharePoint Groups
 
.DESCRIPTION
 Update McKean Managers SharePoint Groups
 
.PARAMETER LogFile
Defaults to 'Generate-LogFileName' output
 
.PARAMETER ScriptVer
Defaults to 'Get-ScriptVersion' output
 
.PARAMETER ShrPtGrpOU
AD Organizational Unit containing SharePoint Groups. (ex: 'OU=Sharepoint Groups,OU=Groups,OU=McKean,dc=mckean,dc=local')
 
.PARAMETER MgrList
Manager List cdv file name (i.e.: 'mgrlist.csv' or 'McKean Managers.csv')
 
.PARAMETER Subject
SMTP Subject Line
 
.PARAMETER SMTPServer
FQDN of SMTP server
 
.PARAMETER Sender
Sending email addresse
 
.PARAMETER Recipients
 Array of recipient email addresses
 
#>
 #Comment_based_Help

[cmdletbinding(SupportsShouldProcess=$true)] #needed to enable passthru of common paramaters like -verbose

 param(
  [string]
  $LogFile           = $(New-LogFileName)
  ,
  [string]
  $ScriptVer         = $(if ($pscommandpath -eq '')
                          { $((get-date).ToString("yyyyMMdd-HHmmss"))}
                         else 
                          {(Get-Item $PSCommandPath).lastwritetime.tostring("yyyyMMdd-HHmmss")}
                        )
  ,
  [string]
  $ShrPtGrpOU        = "OU=Sharepoint Groups,OU=Groups,OU=McKean,dc=mckean,dc=local"
  ,
  [string]
  $MgrList           = $(get-filename -title "Select HRB .CSV Input File " -initialDirectory '\\vab-vfp-01\hrb_updates$' -Filter 'CSV Files (*.csv)|*.csv|All Files (*.*)|*.*')
  ,
  [string]
  $Subject           = "Sharepoint Managers Group Update"
  ,
  [string]
  $SMTPServer        = "smtp.mckean.local"
  ,
  [string]
  $Sender            = "$([environment]::UserName) <$([environment]::UserName)@$([environment]::UserDomainName).local>"
  ,
  [string[]]
  $Recipients        = @("Dan Murray <dmurray@mckean-defense.com>","HelpDesk <HelpDesk@mckean-defense.com>")

 ) # param end

 begin{
    $mail         = @{}
    $mail.SmtpServer = $SMTPServer
    $mail.from       = $Sender
    $mail.subject = $Subject
    $mail.body    = ('#assign dmurray','#mute','#close',$msg|Out-String)
    $mail.to      = $Recipients
    if (Test-Path $Logfile){$mail.attachments = $Logfile}

    # Regexes
    # ===================================================================
    # Regex's used
    # [where 'Management Level' -match '[1-9A].*'] ==> All managers (and executives)
    # [where 'Management Level' -match '[1-9].*'] ==> All Executives
    # ===================================================================
    $RgX = @("'[1-9A].*'","'[1-9].*'")

    # Define each groups' name (samaaccountname), Description field, and Where string for selecting users from MgrList
    $ShrPtMgrsGrp        = "HRB-Managers","McKean Managers","'Management Level' -match '[1-9A].*'"
    $ShrPtExecGrp        = "HRB-Executives","McKean Executives","'Management Level' -match '[1-9].*'"

    # combine the group definitions for loop processing (scalability)
    $ShrPtGrps           = $ShrPtMgrsGrp,$ShrPtExecGrp

 } # begin (vars and such)

 process{
    try{
        #Abort if no MgrList is supplied
        if ($MgrList.Length -eq 0 -or $MgrList -eq $null -or $MgrList -eq "" ) {
            Write-LogInfo -logpath $logfile -ToScreen -TimeStamp -Message "$((get-date).ToString("yyyyMMdd-HHmmss")) Nothing to process, exiting script."
            Write-LogInfo -logpath $logfile -ToScreen -TimeStamp -Message "$((get-date).ToString("yyyyMMdd-HHmmss")) Goodbye."
            throw "No Manager List supplied" 
        } #if ($MgrList.Length -eq 0 -or $MgrList -eq $null -or $MgrList -eq "" )
        else {
            $msg = "$($MgrList) Seems OK" 
            Write-LogInfo -logpath $logfile -timestamp -ToScreen -message $msg
        } #else MgrList is supplied

        #region update the Executives
            $tname='HRB-Executives'
            Write-Verbose "update the Executives"

            #region check for existing group, create if not existing
                if (!(Get-ADGroup $tname)) {
                Write-LogInfo -LogPath $logfile -ToScreen -TimeStamp -Message "Creating group $tname"
                New-ADGroup $tname -Path $ShrPtGrpOU -Description $tdesc -GroupScope Global
                } #if (!(Get-ADGroup $tname))
            #endregion check for existing group, create if not existing
 
            #region remove existing members
                Write-LogInfo -LogPath $logfile -TimeStamp -ToScreen -message "Cleaning group: $($tname)"
                (get-adgroupmember -identity $tname)|
                    %{
                    Write-LogInfo -LogPath $logfile -TimeStamp -ToScreen -Message " - '$($_.name)'"
                    remove-adgroupmember -identity $tname -members $_ -Confirm:$false
                    }
            #endregion remove existing members

            #region (re) add members
                Write-LogInfo -logpath $logfile -timestamp -toscreen -message "Populating group: $($tname)"
                $newmembers=((import-csv -path $MgrList)|where 'Management Level' -match '[1-9].*')
                Write-Verbose "(re) add $($newmembers.count) Executives..."
                foreach($mbr in $newmembers) { #foreach($mbr in $newmembers)
                    if ($mbr.'employee id')
                        {$t_id=[string][int]$mbr.'employee id'} # if
                    else 
                        {$t_id=[string][int]$mbr.'File Number'} # else
        
                    $t_usr=(Get-ADUser -Filter "employeeid -like '$($t_id)'")
                    $msg=" Adding $($t_usr.name)"
                    Write-LogInfo -logpath $logfile -timestamp -ToScreen -message $msg
                    Add-ADGroupMember -identity $tname -members $($t_usr.SamAccountName) -confirm:$false -ea 0
                } #foreach($mbr in $newmembers)
            #endregion (re) add members
        #endregion update the Executives

        #region update the Managers
            $tname='HRB-Managers'
            Write-Verbose "Processing $tname" -Verbose

            #region check for existing group, create if not existing
                if (!(Get-ADGroup $tname)) {
                    try {
                        $msg="Creating group '$tname'"
                        New-ADGroup $tname -Path $ShrPtGrpOU -Description $tdesc -GroupScope Global
                        Write-LogInfo -logpath $logfile -timestamp -ToScreen -message $msg
                    } #try
                    Catch{
                        $msg="Unable to create group '$tname'"
                        Write-LogError -logpath $logfile -timestamp -ToScreen -message $msg
                    } #Catch
                } #if (!(Get-ADGroup $tname))
                else {Write-Verbose " No need to create $tname" -Verbose}
            #endregion check for existing group, create if not existing

            #region remove existing members
                Write-Verbose " Remove existing members" -Verbose
                Write-LogInfo -logpath $logfile -TimeStamp -ToScreen -message "Cleaning group: $($tname)"
                (get-adgroupmember -identity $tname)|%{
                    try{
                        remove-adgroupmember -identity $tname -members $_ -Confirm:$false
                        Write-LogInfo -logpath $logfile -timestamp -ToScreen -message " - '$($_.name)'"
                        }#try{}
                    catch{
                        Write-LogError -logpath $logfile -timestamp -ToScreen -message " Unable to remove '$($_.name)'"
                        }#catch{}
                } #(get-adgroupmember -identity $tname)|%{
            #endregion remove existing members

            #region (re) add members
                Write-LogInfo -logpath $logfile -timestamp -ToScreen -message "Populating $($tname)"
                $newmembers=((import-csv -path $MgrList)|where 'Management Level' -match '[1-9A].*')
                Write-Verbose "(re) add $($newmembers.count) Managers..."
                foreach($mbr in $newmembers) { #foreach($mbr in $newmembers)
                    if ($mbr.'employee id')
                        {$t_id=[string][int]$mbr.'employee id'} #if
                    else 
                        {$t_id=[string][int]$mbr.'File Number'} #else
            
                    $t_usr=(Get-ADUser -Filter "employeeid -like '$($t_id)'")
                    $msg=" Adding $($t_usr.name)"
                    Write-LogInfo -LogPath $logfile -TimeStamp -ToScreen -message $msg
                    Add-ADGroupMember -identity $tname -members $($t_usr.SamAccountName) -confirm:$false -ea 0
                } #foreach($mbr in $newmembers)
            #endregion (re) add members

        #endregion update the Managers

        #region Relocate the datafile
            try {
                $dest="$(split-path $MgrList)\completed\$((Get-Item $MgrList).basename)-cmplt-$((get-date).ToString("yyyyMMMdd-HHmm").ToUpper())$((Get-Item $MgrList).extension)";$dest
                move-item $MgrList -Destination $dest
            } #try
            Catch{
                $msg = "Could not relocate $mgrList",$Error[0].Exception.Message -join "; "
                Write-LogError  -LogPath $logfile -TimeStamp -ToScreen -Message $msg
            } #Catch
        #endregion Relocate the datafile


    } # try

    catch{
    } # Catch

 } # process

 end{
    Send-MailMessage @mail
    Remove-Item $LogFile
 } # end



} #function UpdateMcKeanManagersSharePointGroups
Function Write-LogError {
  <#
  .SYNOPSIS
    Writes error message to specified log file
 
  .DESCRIPTION
    Appends a new error message to the specified log file. Automatically prefixes line with ERROR:
 
  .PARAMETER LogPath
    Mandatory. Full path of the log file you want to write to. Example: C:\Windows\Temp\Test_Script.log
 
  .PARAMETER Message
    Mandatory. The description of the error you want to pass (pass your own or use $_.Exception)
 
  .PARAMETER TimeStamp
    Optional. When parameter specified will append the current date and time to the end of the line. Useful for knowing
    when a task started and stopped.
 
  .PARAMETER ExitGracefully
    Optional. If parameter specified, then runs Stop-Log and then exits script
 
  .PARAMETER ToScreen
    Optional. When parameter specified will display the content to screen as well as write to log file. This provides an additional
    another option to write content to screen as opposed to using debug mode.
 
  .INPUTS
    Parameters above
 
  .OUTPUTS
    None
 
  .NOTES
    Version: 1.0
    Author: Luca Sturlese
    Creation Date: 10/05/12
    Purpose/Change: Initial function development.
 
    Version: 1.1
    Author: Luca Sturlese
    Creation Date: 19/05/12
    Purpose/Change: Added debug mode support. Added -ExitGracefully parameter functionality.
 
    Version: 1.2
    Author: Luca Sturlese
    Creation Date: 02/09/15
    Purpose/Change: Changed function name to use approved PowerShell Verbs. Improved help documentation.
 
    Version: 1.3
    Author: Luca Sturlese
    Creation Date: 02/09/15
    Purpose/Change: Changed parameter name from ErrorDesc to Message to improve consistency across functions.
 
    Version: 1.4
    Author: Luca Sturlese
    Creation Date: 03/09/15
    Purpose/Change: Improved readability and cleaniness of error writing.
 
    Version: 1.5
    Author: Luca Sturlese
    Creation Date: 12/09/15
    Purpose/Change: Changed -ExitGracefully parameter to switch type so no longer need to specify $True or $False (see example for info).
 
    Version: 1.6
    Author: Luca Sturlese
    Creation Date: 12/09/15
    Purpose/Change: Added -TimeStamp parameter which append a timestamp to the end of the line. Useful for knowing when a task started and stopped.
 
    Version: 1.7
    Author: Luca Sturlese
    Creation Date: 12/09/15
    Purpose/Change: Added -ToScreen parameter which will display content to screen as well as write to the log file.
 
  .LINK
    http://9to5IT.com/powershell-logging-v2-easily-create-log-files
 
  .EXAMPLE
    Write-LogError -LogPath "C:\Windows\Temp\Test_Script.log" -Message $_.Exception -ExitGracefully
 
    Writes a new error log message to a new line in the specified log file. Once the error has been written,
    the Stop-Log function is excuted and the calling script is exited.
 
  .EXAMPLE
    Write-LogError -LogPath "C:\Windows\Temp\Test_Script.log" -Message $_.Exception
 
    Writes a new error log message to a new line in the specified log file, but does not execute the Stop-Log
    function, nor does it exit the calling script. In other words, the only thing that occurs is an error message
    is written to the log file and that is it.
 
    Note: If you don't specify the -ExitGracefully parameter, then the script will not exit on error.
  #>


  [cmdletbinding(SupportsShouldProcess=$true)]

  Param (
    [Parameter(Mandatory=$true,Position=0)][string]$LogPath,
    [Parameter(Mandatory=$true,Position=1,ValueFromPipeline=$true)][string]$Message,
    [Parameter(Mandatory=$false,Position=3)][switch]$TimeStamp,
    [Parameter(Mandatory=$false,Position=4)][switch]$ExitGracefully,
    [Parameter(Mandatory=$false,Position=5)][switch]$ToScreen
  )

  Process {
    Write-Debug "LogError"
    #Add TimeStamp to message if specified
    If ( $TimeStamp -eq $True ) {
      $Message = '['+$([DateTime]::Now)+'] '+$Message
    }

    #Write Content to Log
    Add-Content -Path $LogPath -Value "ERROR: $Message"

    #Write to screen for debug mode
    Write-Debug "ERROR: $Message"

    #Write to scren for ToScreen mode
    If ( $ToScreen -eq $True ) {
      Write-Output "ERROR: $Message"
    }

    #If $ExitGracefully = True then run Log-Finish and exit script
    If ( $ExitGracefully -eq $True ){
      Add-Content -Path $LogPath -Value " "
      Stop-Log -LogPath $LogPath
      Break
    }
  }
} # Function Write-LogError
Function Write-LogInfo {
  <#
  .SYNOPSIS
    Writes informational message to specified log file
 
  .DESCRIPTION
    Appends a new informational message to the specified log file
 
  .PARAMETER LogPath
    Mandatory. Full path of the log file you want to write to. Example: C:\Windows\Temp\Test_Script.log
 
  .PARAMETER Message
    Mandatory. The string that you want to write to the log
 
  .PARAMETER TimeStamp
    Optional. When parameter specified will append the current date and time to the end of the line. Useful for knowing
    when a task started and stopped.
 
  .PARAMETER ToScreen
    Optional. When parameter specified will display the content to screen as well as write to log file. This provides an additional
    another option to write content to screen as opposed to using debug mode.
 
  .INPUTS
    Parameters above
 
  .OUTPUTS
    None
 
  .NOTES
    Version: 1.0
    Author: Luca Sturlese
    Creation Date: 10/05/12
    Purpose/Change: Initial function development.
 
    Version: 1.1
    Author: Luca Sturlese
    Creation Date: 19/05/12
    Purpose/Change: Added debug mode support.
 
    Version: 1.2
    Author: Luca Sturlese
    Creation Date: 02/09/15
    Purpose/Change: Changed function name to use approved PowerShell Verbs. Improved help documentation.
 
    Version: 1.3
    Author: Luca Sturlese
    Creation Date: 02/09/15
    Purpose/Change: Changed parameter name from LineValue to Message to improve consistency across functions.
 
    Version: 1.4
    Author: Luca Sturlese
    Creation Date: 12/09/15
    Purpose/Change: Added -TimeStamp parameter which append a timestamp to the end of the line. Useful for knowing when a task started and stopped.
 
    Version: 1.5
    Author: Luca Sturlese
    Creation Date: 12/09/15
    Purpose/Change: Added -ToScreen parameter which will display content to screen as well as write to the log file.
 
  .LINK
    http://9to5IT.com/powershell-logging-v2-easily-create-log-files
 
  .EXAMPLE
    Write-LogInfo -LogPath "C:\Windows\Temp\Test_Script.log" -Message "This is a new line which I am appending to the end of the log file."
 
    Writes a new informational log message to a new line in the specified log file.
  #>


  [cmdletbinding(SupportsShouldProcess=$true)]

  Param (
    [Parameter(Mandatory=$true,Position=0)][string]$LogPath,
    [Parameter(Mandatory=$true,Position=1,ValueFromPipeline=$true)][string]$Message,
    [Parameter(Mandatory=$false,Position=2)][switch]$TimeStamp,
    [Parameter(Mandatory=$false,Position=3)][switch]$ToScreen
  )

  Process {
    #Add TimeStamp to message if specified
    If ( $TimeStamp -eq $True ) {
      $Message = '['+$([DateTime]::Now)+'] '+$Message
    }

    #Write Content to Log
    Add-Content -Path $LogPath -Value $Message

    #Write to screen for debug mode
    Write-Debug $Message

    #Write to scren for ToScreen mode
    If ( $ToScreen -eq $True ) {
      Write-Output $Message
    }
  }
} # Function Write-LogInfo
Function Write-LogWarning {
  <#
  .SYNOPSIS
    Writes warning message to specified log file
 
  .DESCRIPTION
    Appends a new warning message to the specified log file. Automatically prefixes line with WARNING:
 
  .PARAMETER LogPath
    Mandatory. Full path of the log file you want to write to. Example: C:\Windows\Temp\Test_Script.log
 
  .PARAMETER Message
    Mandatory. The string that you want to write to the log
 
  .PARAMETER TimeStamp
    Optional. When parameter specified will append the current date and time to the end of the line. Useful for knowing
    when a task started and stopped.
 
  .PARAMETER ToScreen
    Optional. When parameter specified will display the content to screen as well as write to log file. This provides an additional
    another option to write content to screen as opposed to using debug mode.
 
  .INPUTS
    Parameters above
 
  .OUTPUTS
    None
 
  .NOTES
    Version: 1.0
    Author: Luca Sturlese
    Creation Date: 02/09/15
    Purpose/Change: Initial function development.
 
    Version: 1.1
    Author: Luca Sturlese
    Creation Date: 12/09/15
    Purpose/Change: Added -TimeStamp parameter which append a timestamp to the end of the line. Useful for knowing when a task started and stopped.
 
    Version: 1.2
    Author: Luca Sturlese
    Creation Date: 12/09/15
    Purpose/Change: Added -ToScreen parameter which will display content to screen as well as write to the log file.
 
  .LINK
    http://9to5IT.com/powershell-logging-v2-easily-create-log-files
 
  .EXAMPLE
    Write-LogWarning -LogPath "C:\Windows\Temp\Test_Script.log" -Message "This is a warning message."
 
    Writes a new warning log message to a new line in the specified log file.
  #>


  [cmdletbinding(SupportsShouldProcess=$true)]

  Param (
    [Parameter(Mandatory=$true,Position=0)][string]$LogPath,
    [Parameter(Mandatory=$true,Position=1,ValueFromPipeline=$true)][string]$Message,
    [Parameter(Mandatory=$false,Position=2)][switch]$TimeStamp,
    [Parameter(Mandatory=$false,Position=3)][switch]$ToScreen
  )

  Process {
    #Add TimeStamp to message if specified
    If ( $TimeStamp -eq $True ) {
      $Message = '['+$([DateTime]::Now)+'] '+$Message
    }

    #Write Content to Log
    Add-Content -Path $LogPath -Value "WARNING: $Message"

    #Write to screen for debug mode
    Write-Debug "WARNING: $Message"

    #Write to scren for ToScreen mode
    If ( $ToScreen -eq $True ) {
      Write-Output "WARNING: $Message"
    }
  }
} # Function Write-LogWarning



# SIG # Begin signature block
# MIIU8AYJKoZIhvcNAQcCoIIU4TCCFN0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUirZoEt1AQCSK5XD3ARL5NTuP
# Fbeggg/gMIIEmTCCA4GgAwIBAgIPFojwOSVeY45pFDkH5jMLMA0GCSqGSIb3DQEB
# BQUAMIGVMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQg
# TGFrZSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNV
# BAsTGGh0dHA6Ly93d3cudXNlcnRydXN0LmNvbTEdMBsGA1UEAxMUVVROLVVTRVJG
# aXJzdC1PYmplY3QwHhcNMTUxMjMxMDAwMDAwWhcNMTkwNzA5MTg0MDM2WjCBhDEL
# MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE
# BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKjAoBgNVBAMT
# IUNPTU9ETyBTSEEtMSBUaW1lIFN0YW1waW5nIFNpZ25lcjCCASIwDQYJKoZIhvcN
# AQEBBQADggEPADCCAQoCggEBAOnpPd/XNwjJHjiyUlNCbSLxscQGBGue/YJ0UEN9
# xqC7H075AnEmse9D2IOMSPznD5d6muuc3qajDjscRBh1jnilF2n+SRik4rtcTv6O
# KlR6UPDV9syR55l51955lNeWM/4Og74iv2MWLKPdKBuvPavql9LxvwQQ5z1IRf0f
# aGXBf1mZacAiMQxibqdcZQEhsGPEIhgn7ub80gA9Ry6ouIZWXQTcExclbhzfRA8V
# zbfbpVd2Qm8AaIKZ0uPB3vCLlFdM7AiQIiHOIiuYDELmQpOUmJPv/QbZP7xbm1Q8
# ILHuatZHesWrgOkwmt7xpD9VTQoJNIp1KdJprZcPUL/4ygkCAwEAAaOB9DCB8TAf
# BgNVHSMEGDAWgBTa7WR0FJwUPKvdmam9WyhNizzJ2DAdBgNVHQ4EFgQUjmstM2v0
# M6eTsxOapeAK9xI1aogwDgYDVR0PAQH/BAQDAgbAMAwGA1UdEwEB/wQCMAAwFgYD
# VR0lAQH/BAwwCgYIKwYBBQUHAwgwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2Ny
# bC51c2VydHJ1c3QuY29tL1VUTi1VU0VSRmlyc3QtT2JqZWN0LmNybDA1BggrBgEF
# BQcBAQQpMCcwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20w
# DQYJKoZIhvcNAQEFBQADggEBALozJEBAjHzbWJ+zYJiy9cAx/usfblD2CuDk5oGt
# Joei3/2z2vRz8wD7KRuJGxU+22tSkyvErDmB1zxnV5o5NuAoCJrjOU+biQl/e8Vh
# f1mJMiUKaq4aPvCiJ6i2w7iH9xYESEE9XNjsn00gMQTZZaHtzWkHUxY93TYCCojr
# QOUGMAu4Fkvc77xVCf/GPhIudrPczkLv+XZX4bcKBUCYWJpdcRaTcYxlgepv84n3
# +3OttOe/2Y5vqgtPJfO44dXddZhogfiqwNGAwsTEOYnB9smebNd0+dmX+E/CmgrN
# Xo/4GengpZ/E8JIh5i15Jcki+cPwOoRXrToW9GOUEB1d0MYwggVbMIIEQ6ADAgEC
# AhBtTXK1yM9OwllPm0eMV3CgMA0GCSqGSIb3DQEBCwUAMH0xCzAJBgNVBAYTAkdC
# MRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcTB1NhbGZvcmQx
# GjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMSMwIQYDVQQDExpDT01PRE8gUlNB
# IENvZGUgU2lnbmluZyBDQTAeFw0xNzAzMjMwMDAwMDBaFw0xOTAzMjMyMzU5NTla
# MIGlMQswCQYDVQQGEwJVUzEOMAwGA1UEEQwFMjM0NTYxCzAJBgNVBAgMAlZBMRcw
# FQYDVQQHDA5WaXJnaW5pYSBCZWFjaDEeMBwGA1UECQwVMjQxMyBIdW50cyBOZWNr
# IFRyYWlsMR8wHQYDVQQKDBZNdXJkYW4gRW50ZXJwcmlzZXMgTExDMR8wHQYDVQQD
# DBZNdXJkYW4gRW50ZXJwcmlzZXMgTExDMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
# MIIBCgKCAQEAi0G6vzn+MSvLUsPtwzrJ0JL/3hXnlwFcJAy0eMjWAEQ+IdSEBrFm
# O4nJep9gWnWV5bsh5Zal/qwG92A0XrTpEe+wxUJKgEicWVVKJgFNfF+Sw25Ac1KB
# DjiZKiyCuaT6N+Zu4Le1HgypskZKtRNUZHEGcG3phZEwIRxzROUqoqmLul1zwzFF
# uU/qBbmsYEMq+B4ZFd7VqBcVusXLxwEb/i4xrBYp6uzM0FwdBZG0anT6lcemjBxt
# fQ0n+ivxQM2GGqkpfS6WkbVb/2xeUDTAcAtpG2u3jUnEoQJUmj6/kN9hJh3r1DbP
# MT8PY6leb72QR6y+EKj/Dfum+kp+He/siQIDAQABo4IBrDCCAagwHwYDVR0jBBgw
# FoAUKZFg/4pN+uv5pmq4z/nmS71JzhIwHQYDVR0OBBYEFDZv/Sb6UOZXd+mYdeqj
# bh3uv6g8MA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoG
# CCsGAQUFBwMDMBEGCWCGSAGG+EIBAQQEAwIEEDBGBgNVHSAEPzA9MDsGDCsGAQQB
# sjEBAgEDAjArMCkGCCsGAQUFBwIBFh1odHRwczovL3NlY3VyZS5jb21vZG8ubmV0
# L0NQUzBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9D
# T01PRE9SU0FDb2RlU2lnbmluZ0NBLmNybDB0BggrBgEFBQcBAQRoMGYwPgYIKwYB
# BQUHMAKGMmh0dHA6Ly9jcnQuY29tb2RvY2EuY29tL0NPTU9ET1JTQUNvZGVTaWdu
# aW5nQ0EuY3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20w
# HQYDVR0RBBYwFIESZG11cnJheUBtdXJkYW4ubmV0MA0GCSqGSIb3DQEBCwUAA4IB
# AQBIimXZ7wtpMw/YsgBNY+7uo25P53Xzy1A1InZkW0ZTMFyncV3v+ZO+sq+T/86D
# EOAv7W6FsBqMMI23hnWfcVuViQkM1UKSazoRKIdN2BhVX42SSN7iYhdBY+Pcel51
# b5HhprHgO1PoW1G6ez2h6U7oJ5IQ44D4jXnuiNQ99zZGR/IdEowxPLQsIC1lxEYh
# efd0k2ot2V4/BTy6ccL7AhA19AArPWtDWzdX8u9RW7Ao8e2Z075jcOzfCBzYTbSC
# JfAJgWSx52cBmHnTOvlWAW7NaD80TLY4CyHJsRjEvnHSiwVDK2AJjnuNjHw4dY8c
# YX7Wn/7ZFyhaJGxAovu2mEKzMIIF4DCCA8igAwIBAgIQLnyHzA6TSlL+lP0ct800
# rzANBgkqhkiG9w0BAQwFADCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0
# ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RP
# IENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBB
# dXRob3JpdHkwHhcNMTMwNTA5MDAwMDAwWhcNMjgwNTA4MjM1OTU5WjB9MQswCQYD
# VQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdT
# YWxmb3JkMRowGAYDVQQKExFDT01PRE8gQ0EgTGltaXRlZDEjMCEGA1UEAxMaQ09N
# T0RPIFJTQSBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
# ggEKAoIBAQCmmJBjd5E0f4rR3elnMRHrzB79MR2zuWJXP5O8W+OfHiQyESdrvFGR
# p8+eniWzX4GoGA8dHiAwDvthe4YJs+P9omidHCydv3Lj5HWg5TUjjsmK7hoMZMfY
# QqF7tVIDSzqwjiNLS2PgIpQ3e9V5kAoUGFEs5v7BEvAcP2FhCoyi3PbDMKrNKBh1
# SMF5WgjNu4xVjPfUdpA6M0ZQc5hc9IVKaw+A3V7Wvf2pL8Al9fl4141fEMJEVTyQ
# PDFGy3CuB6kK46/BAW+QGiPiXzjbxghdR7ODQfAuADcUuRKqeZJSzYcPe9hiKaR+
# ML0btYxytEjy4+gh+V5MYnmLAgaff9ULAgMBAAGjggFRMIIBTTAfBgNVHSMEGDAW
# gBS7r34CPfqm8TyEjq3uOJjs2TIy1DAdBgNVHQ4EFgQUKZFg/4pN+uv5pmq4z/nm
# S71JzhIwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwEwYDVR0l
# BAwwCgYIKwYBBQUHAwMwEQYDVR0gBAowCDAGBgRVHSAAMEwGA1UdHwRFMEMwQaA/
# oD2GO2h0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0NPTU9ET1JTQUNlcnRpZmljYXRp
# b25BdXRob3JpdHkuY3JsMHEGCCsGAQUFBwEBBGUwYzA7BggrBgEFBQcwAoYvaHR0
# cDovL2NydC5jb21vZG9jYS5jb20vQ09NT0RPUlNBQWRkVHJ1c3RDQS5jcnQwJAYI
# KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNvbTANBgkqhkiG9w0BAQwF
# AAOCAgEAAj8COcPu+Mo7id4MbU2x8U6ST6/COCwEzMVjEasJY6+rotcCP8xvGcM9
# 1hoIlP8l2KmIpysQGuCbsQciGlEcOtTh6Qm/5iR0rx57FjFuI+9UUS1SAuJ1CAVM
# 8bdR4VEAxof2bO4QRHZXavHfWGshqknUfDdOvf+2dVRAGDZXZxHNTwLk/vPa/HUX
# 2+y392UJI0kfQ1eD6n4gd2HITfK7ZU2o94VFB696aSdlkClAi997OlE5jKgfcHmt
# bUIgos8MbAOMTM1zB5TnWo46BLqioXwfy2M6FafUFRunUkcyqfS/ZEfRqh9TTjIw
# c8Jvt3iCnVz/RrtrIh2IC/gbqjSm/Iz13X9ljIwxVzHQNuxHoc/Li6jvHBhYxQZ3
# ykubUa9MCEp6j+KjUuKOjswm5LLY5TjCqO3GgZw1a6lYYUoKl7RLQrZVnb6Z53Bt
# WfhtKgx/GWBfDJqIbDCsUgmQFhv/K53b0CDKieoofjKOGd97SDMe12X4rsn4gxST
# dn1k0I7OvjV9/3IxTZ+evR5sL6iPDAZQ+4wns3bJ9ObXwzTijIchhmH+v1V04SF3
# AwpobLvkyanmz1kl63zsRQ55ZmjoIs2475iFTZYRPAmK0H+8KCgT+2rKVI2SXM3C
# ZZgGns5IW9S1N5NGQXwH3c/6Q++6Z2H/fUnguzB9XIDj5hY5S6cxggR6MIIEdgIB
# ATCBkTB9MQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVy
# MRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01PRE8gQ0EgTGltaXRlZDEj
# MCEGA1UEAxMaQ09NT0RPIFJTQSBDb2RlIFNpZ25pbmcgQ0ECEG1NcrXIz07CWU+b
# R4xXcKAwCQYFKw4DAhoFAKB4MBgGCisGAQQBgjcCAQwxCjAIoAKAAKECgAAwGQYJ
# KoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQB
# gjcCARUwIwYJKoZIhvcNAQkEMRYEFLE6ieVyYzHPQ+2UXrBPXcfbIOBtMA0GCSqG
# SIb3DQEBAQUABIIBACxlmaAjKZ3hp9LGUM3EhvZzDkykxuxjNQHS2duqvgS8JH2U
# 1+d6RHy3xga+9dqbRopqDSaaGFA9tuZLSn3vLrlxpQDW9enLOhEoYJE7IPg5h6FD
# GnVObTBVj9XV2n4l5wNqUGOaLJPaZk/3afOh0OEWuDqjiX4qsSnLoE5qyqB6YJWg
# HhFsMNHWEh2j7sdox08/jdoxEhvKPD3+P3XmeLbF/FTxmgoLArm5WK1Xuf5BvZN1
# B874TiQfZ2bJj/gSuVQMtXG/TDlWf/ZMgTrnvHQkoHqxpHSRa/ijs6qUXJNzGUJR
# s1svNmZ8ETY3NhC957cffPDHwUU0yPyJrqh85AGhggJDMIICPwYJKoZIhvcNAQkG
# MYICMDCCAiwCAQEwgakwgZUxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJVVDEXMBUG
# A1UEBxMOU2FsdCBMYWtlIENpdHkxHjAcBgNVBAoTFVRoZSBVU0VSVFJVU1QgTmV0
# d29yazEhMB8GA1UECxMYaHR0cDovL3d3dy51c2VydHJ1c3QuY29tMR0wGwYDVQQD
# ExRVVE4tVVNFUkZpcnN0LU9iamVjdAIPFojwOSVeY45pFDkH5jMLMAkGBSsOAwIa
# BQCgXTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0x
# NzEwMDExMTU1MDdaMCMGCSqGSIb3DQEJBDEWBBQtU2B3zLQSliVPtH+KqLRkdwIL
# jTANBgkqhkiG9w0BAQEFAASCAQBQ/4u3TEf9gYqWaeMLvRjpjNRvQnAb84SkUHxJ
# knXX9OqyzzR1LRvunbyrWp7BjPR+6vuVEjFKCQCfBo5S+dS4Ko+uUCHGtUO0t16H
# VL/bBUK+gEJI0IUK7TtBXhKp77mNsGegau3TnLKo/Zmj1kw9Vit5j19RyG8Mka3u
# 37tbYwt1hjTqmfHGjeNjBWl+YrHrB8VVhma/O5YkGaFgo80k0GzTZ7nuh2P6hW/W
# PZocIG8L3uCWPvWC0gDTAGPSXGfjzzSWzr7W1vSa/ADAHoSUQGTJa2D79IuYG3u2
# NHAY9Iy3eu2/NiO7veWyk6Zw4e78HCxTv+w1QYZIyeXKrGsw
# SIG # End signature block