Tuesday, June 30, 2015

Certificate Expiration Report

Generate-CertificateExpirationReport

<#
    .SYNOPSIS
        Generate report of  SSL certificates that will expire in the next 90 days.
    .DESCRIPTION
        This script runs Check-CertExpiration.ps1 as a background job on multiple web servers in 
        parallel using PowerShell Remoting. It waits for all background jobs to complete
        and retrieves results and errors and generates an html report and a log file that are send out
        by email.
        
    .EXAMPLE
        Generate-CertificateExpirationReport.ps1 -verbose
    .LINK
        "https://technet.microsoft.com/en-us/library/hh847761.aspx"
        "http://blogs.technet.com/b/heyscriptingguy/archive/2010/03/18/hey-scripting-guy-march-18-2010.aspx"
        "http://thesurlyadmin.com/2013/01/21/how-to-create-html-reports/#more-817"

#>

[CmdletBinding()]

Param (

)



Import-Module ActiveDirectory
$Servers = Get-ADComputer -SearchBase 'OU=ProdServers,dc=adatum,dc=local' -Filter {(Name -like "*web*") -and (OperatingSystem -like "Windows*")} | % {$_.Name} | Sort-Object -Property $_.name


Write-Verbose "Number of Servers: $($Servers.count)"

Function CheckSSL {
    $Objs = @()
    $Jobs = @()
    $i = 0
    ForEach ($Server in $Servers) {
        Write-Verbose "Checking certificates on $Server"
        $i++
        $percent = [decimal]::round($i / $Servers.length * 100)
        Write-Progress -activity "Checking SSL Expiration Status on $Server" -status "Percent Complete: $percent %" -PercentComplete ($i / $Servers.count * 100)
        
        Try {        
                Test-WSMan -ComputerName $Server -ErrorAction Stop
                $Jobs += Invoke-Command -ComputerName $Server  -FilePath .\Check-CertExpiration.ps1 -AsJob -ErrorAction SilentlyContinue
        
            } Catch {
                Write-Verbose $_.Exception.Message
                $Properties = @{'ServerName' = $Server
                                'Error' = $_.Exception.Message
                                }
                $Unavailable = New-Object -TypeName PSObject -Property $Properties
                $Objs += $Unavailable

       
            }#End Try-Catch
        
       
        } # End ForEach

    $Objs | Select-Object ServerName,Error
    Write-Verbose "Waiting for jobs to complete..."
    $complete = $false
    while (-not $complete) {
    $arrayJobsInProgress = $Jobs | `
    Where-Object { $_.State -match 'running' }
        if (-not $arrayJobsInProgress) { "All Jobs Have Completed" ; $complete = $true } 
    }# End while

    Write-Verbose "Getting job's results..."
    $Jobs | Receive-Job 2> JobsErrors.log
    Get-job | Remove-Job
    Write-Verbose "Sending results by email."
}# End Function

$Header = @"

"@

$Message = CheckSSL | Select ServerName,ExpirationDate,FriendlyName,Subject,Issuer,Error| Where-Object {$_.ServerName} | sort-object ExpirationDate | ConvertTo-HTML -head $Header –body "

SSL Certificate Expiration Report

" $Message = "The following list of SSL certs will expire in the next 90 days.`n`r$Message" Send-MailMessage -To "admin@adatum.local" -Subject "SSL Certificate Expiration Report" -From $env:ComputerName"@adatum.local" ` -BodyAsHtml $Message ` -SmtpServer "smtp.adatum.local" ` -Attachments "JobsErrors.log"

Check-CertExpiration.ps1


    gci -Path cert:\LocalMachine\My, cert:\LocalMachine\WebHosting -Recurse `
    | ? {$_.NotAfter -lt (Get-Date).AddDays(60)} `
    | ? {$_.NotAfter -gt (Get-Date).AddDays(-30)} `
    | Select -Property `
        @{n='ServerName';e={$env:ComputerName}},`
        @{n='ExpirationDate';e={$_.NotAfter}},`
        @{n='FriendlyName';e={$_.FriendlyName}},`
        @{n='Subject';e={$_.Subject}},`
        @{n='Issuer';e={$_.Issuer}} 



Thursday, March 26, 2015

Automate generation of credentials for service accounts


<#
    .SINOPSIS
        Generate credentials for service accounts.

    .DESCRIPTION
        Uses a login name list to generate a password for each login and export credentials to csv file,
        that can be imported into Keepass.
        Author: Antonio Sotelo
        Email:

    .EXAMPLE
        loginnames.txt contains login names for the service accounts,
        the script generate a password for each login name and export credentials to csv file.
        .\Create-CSVFile -loginsFile "c:\loginnames.txt" -csvFile "c:\SvcAccounts.csv" -verbose

    .LINKS
         References:

         How to export data to CSV in PowerShell?
         http://stackoverflow.com/questions/21047185/how-to-export-data-to-csv-in-powershell

         Generate a random and complex passwords
         https://gallery.technet.microsoft.com/scriptcenter/Generate-a-random-and-5c879ed5

    .NOTES
        Use KeePass 2.28 to import csv file using Generic CSV Importer.
        Then you can export from it and import to Keepass 1.28

#>

[CmdletBinding()]
Param (
    [Parameter(Mandatory=$false)]
    [string]$csvFile = "c:\SvcAccounts.csv",
    [string]$loginsFile = "loginnames.txt"


)

#Load password generator function
. .\New-SWRandomPassword.ps1
$Accounts = Get-Content $loginsFile
$results = @()
Write-Verbose "Generating passwords for each user in the list."
foreach ($Account in $Accounts) {
        Write-Verbose "Generating password for $Account"
        $Password = New-SWRandomPassword -MinPasswordLength 16 -MaxPasswordLength 16

        $Credentials = @{            
                           
               'Login Name'   = $Account                
                Password      = $Password
        }                           
        $results += New-Object PSObject -Property $Credentials  
  
}
Write-Verbose "Finished generating passwords, exporting credentials to $csvFile file."
$results | export-csv -Path $csvFile -NoTypeInformation

Thursday, March 19, 2015

Automating Windows patching for VM templates



# This script will convert template to VM, Power On VM, run Windows Update remotely, reboot VMGuest, shut VM down and finally convert back to template
# From https://communities.vmware.com/message/2470778
# Modified by Antonio Sotelo

# Requires Windows Update PowerShell Module installed on the template to run Get-WUInstall cmdlet.
# https://gallery.technet.microsoft.com/scriptcenter/2d191bcd-3308-4edd-9de2-88dff796b0bc/file/41459/43/PSWindowsUpdate.zip
# Extract to %WINDIR%\System32\WindowsPowerShell\v1.0\Modules

# Connect to vCenter
# http://blogs.vmware.com/PowerCLI/2013/03/back-to-basics-connecting-to-vcenter-or-a-vsphere-host.html
# Get the Credentials (Using VICredentialStore "C:\Scripts\vicredentials.xml" is created running the PowerCLI  console as the user account that runs the scheduled task.
# Example of scheduled task command: 
#   powershell.exe -PSconsolefile "c:\Program Files (x86)\VMware\Infrastructure\vSphere PowerCLI\vim.psc1" "& 'C:\Scripts\PatchVMTemplates.ps1'"
#   Scheduled to run second Tuesday of the month

$vicreds = Get-VICredentialStoreItem -file  "C:\Scripts\vicredentials.xml"

Connect-VIServer $vicreds.host -User $vicreds.User -Password $vicreds.Password


Function PatchVMTemplate ($VMTemplate){
# Convert template to VM
Set-Template -Template $VMTemplate -ToVM -Confirm:$false -RunAsync
Start-sleep -s 30

# Start VM template
# Thanks to http://theboywonder.co.uk/2012/10/19/catching-virtual-machine-questions-with-powercli/
try
{
    try
    {
        Start-VM -VM $VMTemplate -ErrorAction Stop -ErrorVariable custErr
    }
    catch [System.Management.Automation.ActionPreferenceStopException]
    {
        throw $_.Exception
    }
}
catch [VMware.VimAutomation.ViCore.Types.V1.ErrorHandling.VMBlockedByQuestionException]
{
        Get-VMQuestion -VM $VMTemplate | Set-VMQuestion –Option "I copied it" -Confirm:$false 
}

Start-sleep -s 120
 
# Create variables for Guest OS credentials - This is needed for the Invoke-VMScript cmdlet to be able to execute actions inside the Guest.
$Username = "administrator"
# Note: Password is encrypted in OSPwd.txt which needs to be created beforehand using this command: read-host -assecurestring | convertfrom-securestring | out-file C:\Scripts\OSPwd.txt
# This file is created running the PowerCLI console as the user account that runs the scheduled task.
$OSPwd = cat C:\Scripts\OSPwd1.txt | convertto-securestring
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $Username, $OSPwd

# The following is the cmdlet that will invoke the Get-WUInstall inside the GuestVM to install all available Windows updates.
# Requires Windows Update PowerShell Module installed on the template to run Get-WUInstall cmdlet.
# Results are exported to a log file to see the patches installed and related results.
Invoke-VMScript -ScriptType PowerShell -ScriptText "Get-WUInstall –WindowsUpdate –AcceptAll –AutoReboot" -VM $VMTemplate -GuestCredential $Cred | Out-file -Filepath C:\$VMTemplate-WUResults.log # -Append
 
Start-sleep -s 120
 
# Restart VMGuest one more time in case Windows Update requires it and for whatever reason the –AutoReboot switch didn’t complete it.
Restart-VMGuest -VM $VMTemplate -Confirm:$false
 
Start-sleep -s 300

# Shutdown the server and convert it back to Template.
Shutdown-VMGuest $VMTemplate -Confirm:$false
Start-sleep -s 120
Set-VM –VM $VMTemplate -ToTemplate -Confirm:$false

} #End of Function

PatchVMTemplate "Test_Template"


# Send an email with WU Results
$EmailTo = "admin@somewhere.com"
$EmailSubject = "WSUS Patching for VM Templates"
  Send-MailMessage -To $EmailTo `
  -Subject $EmailSubject -From "WSUSReporting@somewhere.com" `
  -Body "VM templates have been patched. See attachments for details. This is an automated message. Do not reply to this email." `
  -Attachments "C:\Test_Template-WUResults.log"
  -SmtpServer "mail.smtpserver.com"



Changing Application Pool's CPU settings.


<#
     .SYNOPSIS
        Change Application Pool's CPU settings.

     .DESCRIPTION
        Sets CPU Limit(percent) to 80% and CPU Limit Action to "Throttle Under Load"
        for all application pools on Windows 2012+

     .PARAMETER ApplicationPoolName
        Name of the Application Pool.

     .LINK
        References:
        http://www.iis.net/learn/manage/powershell/powershell-snap-in-making-simple-configuration-changes-to-web-sites-and-application-pools
        http://stackoverflow.com/questions/11187304/how-to-set-iis-applicationpool-private-memory-limit-value-using-powershell
     
     .NOTES
        Author: Antonio Sotelo
        Email: 

     .EXAMPLE
        Set-AppPoolCPUDefaults -Verbose
        Changes default app pool's cpu settings to cpu= 80% and cpu action= throttle under load.

        Set-CPUSettings -ApplicationPoolName DefaultAppPool -Verbose -verbose
        Changes all app pool's cpu settings to cpu= 80% and cpu action= throttle under load.
#>


Function Set-AppPoolCPUDefaults () {
[cmdletbinding()]
    param (
    [Parameter( Mandatory=$False)]
        [int]$Percent = 80000,
    [Parameter( Mandatory=$False)]
        [string]$Action = "ThrottleUnderLoad"   
                
    )

    Set-WebConfiguration -filter '/system.applicationHost/applicationPools/applicationPoolDefaults/cpu/@limit' -PSPath IIS:\ -value $Percent
    Set-WebConfiguration -filter '/system.applicationHost/applicationPools/applicationPoolDefaults/cpu/@action' -PSPath IIS:\ -value $Action

    Write-Verbose "Default CPU Limit = $((Get-WebConfiguration /system.applicationHost/applicationPools/applicationPoolDefaults).cpu.limit)"
    Write-Verbose "Default CPU Action = $((Get-WebConfiguration /system.applicationHost/applicationPools/applicationPoolDefaults).cpu.action)"

}#End of function

Function Set-CPUSettings (){
[cmdletbinding()]
    param (
    [Parameter( Mandatory=$False)]
        [string]$ApplicationPoolName,

    [Parameter( Mandatory=$False)]
        [int]$Percent = 80000,
    [Parameter( Mandatory=$False)]
        [string]$Action = "ThrottleUnderLoad"   
                
    )

    Set-ItemProperty IIS:\AppPools\$ApplicationPoolName -Name cpu -Value @{limit=$Percent;action=$Action}
    $cpuLimit = (Get-ItemProperty IIS:\AppPools\$ApplicationPoolName -Name cpu).limit
    $cpuAction = (Get-ItemProperty IIS:\AppPools\$ApplicationPoolName -Name cpu).action
    Write-Verbose "$ApplicationPoolName CPU settings: CPU limit = $cpuLimit , CPU action = $cpuAction"

}#End of function

Write-Output "Changing Application Pool Default CPU settings."
Set-AppPoolCPUDefaults -Verbose

Write-Output "Changing CPU settings for all Application Pools on $env:ComputerName "

get-item IIS:\AppPools\* | %{

Set-CPUSettings -ApplicationPoolName $_.name -Verbose

}



Friday, February 27, 2015

Changing Application Pool's recycle time


# Load Web Administration module
Import-Module WebAdministration

# Process idle timeout - Amount of time (in minutes) a worker process will remain idle before it shuts down
$idleTimeOut = "20"
# RegularTimeIntervalMinutes - Period of time (in minutes) after which the application pool will recycle.
$PeriodicRestart = "0"

function Set-ApplicationPoolRecycleTimes {
 
    param (
        [string]$ApplicationPoolName,
        [string[]]$RestartTimes
    )
     
      
    Write-Output "Updating recycle times for $ApplicationPoolName"
     
    # Delete all existing recycle times
    Clear-ItemProperty IIS:\AppPools\$ApplicationPoolName -Name Recycling.periodicRestart.schedule
     
    foreach ($restartTime in $RestartTimes) {
 
        Write-Output "Adding recycle at $restartTime"
        # Set the application pool to restart at the time we want
        New-ItemProperty -Path "IIS:\AppPools\$ApplicationPoolName" -Name Recycling.periodicRestart.schedule -Value @{value=$restartTime}
         
    } # End foreach restarttime
     
} # End function Set-ApplicationPoolRecycleTimes


function Set-RecyclingTimeoutSettings {
 
    param (
        [string]$ApplicationPoolName        
    )
     
    Write-Output "Setting worker process idle timeout to $idleTimeOut min. and periodic restart time to $PeriodicRestart for $ApplicationPoolName."
    $Pool = Get-Item IIS:\AppPools\"$ApplicationPoolName"
    #  A value of 0 means the process does not shut down after an idle timeout.
    $Pool.ProcessModel.IdleTimeout = [TimeSpan]::FromMinutes($idleTimeOut)
    # A value of 0 means the application pool does not recycle on a regular interval.
    $Pool.Recycling.PeriodicRestart.Time = [TimeSpan]::FromMinutes($PeriodicRestart)
    $Pool | Set-Item
      
} # End function RecyclingTimeoutSettings

# Get all app pools and change the iddle time-out and recycle time settings for each one of them
get-item IIS:\AppPools\* | %{
# Get a random specific time between 3-5 AM
$Offset = (Get-Random -Minimum 1 -Maximum 120) + 180
$restartat = (New-TimeSpan -Minutes $Offset).ToString()
$restartat = $restartat.Substring(0,5)
#$restartat = $null # comment out this line to disable specific time
# Set recycle time out settings
Set-RecyclingTimeoutSettings -ApplicationPoolName $_.name
# Set recycle time
Set-ApplicationPoolRecycleTimes -ApplicationPoolName $_.name -RestartTimes $restartat
}



Friday, February 13, 2015

Automatic log off RDP users


# This script will log off any RDP users with names that contains "user" that have been disconnected for over 30 minutes
# 


$idteTimeOut = 30 # enter time in minutes only
$rdpUser = "user" # enter name string for searching

function RemoveSpace([string]$text) {  
    $private:array = $text.Split(" ", `
    [StringSplitOptions]::RemoveEmptyEntries)
    [string]::Join(" ", $array) }

# Quser - displays information about user sessions on a Remote Desktop Session Host (RD Session Host) server.
$quser = quser
foreach ($sessionString in $quser) {
    $sessionString = RemoveSpace($sessionString)
    $session = $sessionString.split()
    #$session[0] contains USERNAME
    If ($session[0].Contains($rdpUser)) { 
        #$session[2] contains STATE, there is no SESSIONNAME for Disconnected user
        If ($session[2].Equals("Disc")) {
            #Write-Output $session[0]
            # $session[3] contains TIME, there is no SESSIONNAME for Disconnected user
            # Check TIME string if is less than a min make it 0
            If ($session[3].Contains(".")) {
                $session[3] = "0"
            }
            
            # Convert TIME string into h:m format string
            If (!($session[3].Contains(":"))) {
                $session[3] = "0:" + $session[3]
            }
            # Convert TIME string minutes(using timespan) into a number
            $strNum = ([timespan]$session[3] | % {$_.TotalMinutes})
            [int]$intNum = [convert]::ToInt32($strNum, 10)
                # If the number of minutes is greater than idle time-out log off user
                If ($intNum -gt $idteTimeOut) {
                # $session[1] contains ID for logoff command, there is no SESSIONNAME for Disconnected user 
                $Result = logoff $session[1]
                }
        }
    }
    }
$quser = quser
Write-Output $quser


Friday, January 16, 2015

Powershell DSC

Setting up Pull Server
Download WMF 5.0 to your 2012 VM from:

Open Powershell console and run the following command:

Install-Module xPSDesiredStateConfiguration -MinimumVersion 3.0.1 –Force

Accept the offer to download NuGet_anycpu.exe.
Create and run the following script.
configuration NewPullServer
{
param
(
[string[]]$ComputerName = ‘localhost’
)

    Import-DSCResource -ModuleName xPSDesiredStateConfiguration

    Node $ComputerName
{
WindowsFeature DSCServiceFeature
{
Ensure = “Present”
Name   = “DSC-Service”
}

        xDscWebService PSDSCPullServer
{
Ensure                  = “Present”
EndpointName            = “PSDSCPullServer”
Port                    = 8080
PhysicalPath            = “$env:SystemDrive\inetpub\wwwroot\PSDSCPullServer”
CertificateThumbPrint   = “AllowUnencryptedTraffic”
ModulePath              = “$env:PROGRAMFILES\WindowsPowerShell\DscService\Modules”
ConfigurationPath       = “$env:PROGRAMFILES\WindowsPowerShell\DscService\Configuration”
State                   = “Started”
DependsOn               = “[WindowsFeature]DSCServiceFeature”
}

        xDscWebService PSDSCComplianceServer
{
Ensure                  = “Present”
EndpointName            = “PSDSCComplianceServer”
Port                    = 9080
PhysicalPath            = “$env:SystemDrive\inetpub\wwwroot\PSDSCComplianceServer”
CertificateThumbPrint   = “AllowUnencryptedTraffic”
State                   = “Started”
IsComplianceServer      = $true
DependsOn               = (“[WindowsFeature]DSCServiceFeature”,”[xDSCWebService]PSDSCPullServer”)
}
}
}

#This line actually calls the function above to create the MOF file.

NewPullServer –ComputerName server01.comtoso.local
Modules for Dsc Pull server are installed in:












Modules to deploy Dsc Resources are installed in: