Last Logon Date AD Users

source: https://gallery.technet.microsoft.com/scriptcenter/Get-Last-Logon-for-Users-c8e3eab2

The “lastLogon” Active Directory attribute is a property that is not replicated throughout the Domain Controllers.  This attribute is stored on the domain controller that received the authentication request and updated its property accordingly.  Because of this behavior, you have have experienced issues where Domain Controllers in other sites have old or empty lastLogon information.  This makes it difficult to be sure an account is truly inactive without verifying on each Domain Controller.  This can be a problem for environments that have tens or hundreds of Domain Controllers across its enterprise.

I was faced with a problem of writing a script, and like many, developed a seemingly simple solution.  The problem was the runtime was very long for the amount of Domain Controllers / User accounts for the environment.  I sought out to find the solution to this exceedingly long runtime, and I finally did.

This PowerShell will query each of your Domain Controllers only once and produce the most recent logon date/time.

To protect the informaiton about my directory, lets say my environment is between 5 and 10 Domain Controllers, with between 15 – 25k user accounts.  My runtime is between 4-5 minutes for the entire directory!  Which is a far cry faster than the hours other methods produce.

By default, this script will return the entire directory ($Username=*) and save to a CSV ($FileName).  You may call the function with a -Username to return a single account, and this will output on screen instead of a file.

<########################################################################### 
    The purpose of this PowerShell script is to collect the last logon  
    for user accounts on each DC in the domain, evaluate, and return the 
    most recent logon value. 
 
        Author:   Jeremy Reeves 
        Modified: 02/14/2018 
        Notes:    Must have RSAT Tools if running on a workstation 
 
Note: Added enabled true/false to output
###########################################################################> 
 
 
Import-Module ActiveDirectory 
 
function Get-ADUsersLastLogon($Username="*") { 
 
    $FilePath_Prefix = "C:\temp\UserLastLogon-" 
 
    function Msg ($Txt="") { 
        Write-Host "$([DateTime]::Now)    $Txt" 
    } 
 
    #Cycle each DC and gather user account lastlogon attributes 
     
    $List = @() #Define Array 
    (Get-ADDomain).ReplicaDirectoryServers | Sort | % { 
 
        $DC = $_ 
        Msg "Reading $DC" 
        $List += Get-ADUser -Server $_ -Filter "samaccountname -like '$Username'" -Properties LastLogon | Select samaccountname,lastlogon,enabled,@{n='DC';e={$DC}} 
 
    } 
 
    Msg "Sorting for most recent lastlogon" 
     
    $LatestLogOn = @() #Define Array 
    $List | Group-Object -Property samaccountname | % { 
 
        $LatestLogOn += ($_.Group | Sort -prop lastlogon -Descending)[0] 
 
    } 
     
    $List.Clear() 
 
    if ($Username -eq "*") { #$Username variable was not set.    Running against all user accounts and exporting to a file. 
 
        $FileName = "$FilePath_Prefix$([DateTime]::Now.ToString("yyyyMMdd-HHmmss")).csv" 
         
        try { 
 
            $LatestLogOn | Select samaccountname, lastlogon, @{n='lastlogondatetime';e={[datetime]::FromFileTime($_.lastlogon)}}, Enabled, DC | Export-CSV -Path $FileName -NoTypeInformation -Force 
            Msg "Exported results. $FileName" 
 
        } catch { 
 
            Msg "Export Failed. $FileName" 
 
        } 
 
    } else { #$Username variable was set, and may refer to a single user account. 
 
        if ($LatestLogOn) { $LatestLogOn | Select samaccountname, @{n='lastlogon';e={[datetime]::FromFileTime($_.lastlogon)}}, Enabled, DC | FT } else { Msg "$Username not found." } 
 
    } 
 
    $LatestLogon.Clear() 
 
} 

Get Office 365 users with a specific license type via Powershell

It can sometimes be useful to get a list of Office 365 users with a specific license type via PowerShell. Instead of logging into the Office 365 portal and using a filtered view in the admin center, you can do it straight from the command line.

  • Connect to Office 365 via Powershell. If this cmdlet doesn’t work for you, follow this quick guide for instructions on installing the required PowerShell module.

Connect-MsolService

  • Run Get-MsolAccountSku to get a list of the current licenses in your Office 365 tenant. Make a note of the AccountSkuId value for the license you want to filter on.

Get-MsolAccountSku

Get-MsolAccountSku Information
  • Now you can edit this short script to get the users matching that license. In this case, we’re getting users with the EnterprisePremium license.

Get-MsolUser | Where-Object {($_.licenses).AccountSkuId -match "EnterprisePremium"}

Replace EnterprisePremium with the AccountSkuID you’re trying to filter by. Since we’re using the -match operator we don’t need to type the entire AccountSkuID, we can just type enough of it to ensure that we’re only retrieving that specific one.

The script can be tweaked for specific use

Get-MsolUser -MaxResults 100000 | Where-Object {($_.licenses).AccountSkuId -match "EnterprisePremium"} | ft UserPrincipalName, IsLicensed | Out-File c:\temp\E3.csv

Get-MsolUser With Specific Office 365 License

Export these users to a text document

You can export these users to a text document using the Out-File cmdlet.

Get-MsolUser | Where-Object {($_.licenses).AccountSkuId -match "EnterprisePremium"} | Out-file C:\temp\EnterprisePremiumUsers.csv

Source: https://gcits.com/knowledge-base/get-office-365-users-specific-license-type-via-powershell/

Terminal Server Inactive Printer Ports

During the restart of a Terminal Server, inactive TS ports should be deleted. When these inactive ports are not deleted, over time, a server can become sluggish or even hang because of this. When there are a lot of Inactive TS Ports in the registry, printer redirection may also suffer.

If you are experiencing OS performance, Print spooler or RDS printer redirection hangs, check the presences of Inactive TS Ports under the key:

HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{28d78fad-5a12-11d1-ae5b-0000f803a8c2}\##?#Root#RDPBUS#0000#{28d78fad-5a12-11d1-ae5b-0000f803a8c2}

If the subkeys with #TS001\device parameters in it have a “Port Description” with “Inactive TS Port” then the entier root key should be deleted.

With the powershell script below, it is possible to delete these Inactive TS Ports from a remote machine. The scripts reads an OU in the Active Directory where all RDSH servers are located and then it will delete all Inactive TS Ports from those servers.

#Get RDSH Servers
$servers = Get-ADComputer -Filter * -SearchBase "OU=Netherlands, OU=Session Hosts, OU=RDS2012, OU=Servers, OU=Infra,DC=infra,DC=imtech,DC=NL"  

#Delete inactive TS Ports (https://archive.codeplex.com/?p=inactivetsport)
foreach ($server in $servers) {
    $RemoteComputer =$server.name 
    if (Test-Connection -ComputerName $RemoteComputer -Count 1 -ErrorAction SilentlyContinue) { 
        Invoke-Command -ComputerName $RemoteComputer -ScriptBlock {
            $Gegevens = Get-ChildItem -path 'HKLM:SYSTEM\CurrentControlSet\Control\DeviceClasses\{28d78fad-5a12-11d1-ae5b-0000f803a8c2}\##?#ROOT#RDPBUS#0000#{28d78fad-5a12-11d1-ae5b-0000f803a8c2}' -Recurse
            ($gegevens.Name ) -replace "\\Device parameters" | Select-Object -Unique | ForEach-Object { 
                $subkey = ($_ -replace "HKEY_LOCAL_MACHINE\\" , "HKLM:\") + "\Device Parameters"         
                $PortDescription = (Get-itemproperty -path $subkey)."Port Description"
                if ($PortDescription -eq "Inactive TS Port") {
                    $subkeydelete = ($_ -replace "HKEY_LOCAL_MACHINE\\" , "HKLM:\")
                    write-host "delete subkey from $env:COMPUTERNAME => $subkeydelete"
                    Remove-Item -Path $subkeydelete -Recurse                   
                }
            }
        } 
    }
}

For more information about this issue in Windows Server 2008 please check the site: https://archive.codeplex.com/?p=inactivetsport

Create a Dynamics NAV NST Instance with Powershell

How to create a NST instance with a powershell script:

 

Set-ExecutionPolicy -ExecutionPolicy Unrestricted
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Unrestricted

Import-Module "C:\Program Files\Microsoft Dynamics NAV\100\Service\NavAdminTool.ps1" -DisableNameChecking

# Set varaibles for NST
$NAVServiceInstance = 'instance-name'
$DatabaseName = 'database-name'
$DatabaseServer = 'database-server'
$NAVServiceUser = 'service-account'
$NAVServiceUserPW = 'service-account-password'

$DefaultTimeZone = 'Server Time Zone'
$MaxUploadSize = 2047
$EnableTaskScheduler = 'False'

$UseNTLM = $TRUE

$SOAPMaxMsgSize = '5120'

$ChangeTimeout = $FALSE
$IdleClientTimeout = '01:30:00'

$IsNAS = $FALSE
$NASArgument = 'JOBQUEUE'
$NASCodeunit = '450'
$NASMethod = ''
$DefaultCompany = ''

$IsNOR = $FALSE
$LanguageID = '1044'
$Language = 'no-NO'

# NAV Service Account
$secpasswd = ConvertTo-SecureString $NAVServiceUserPW -AsPlainText -Force
$mycreds = New-Object System.Management.Automation.PSCredential ($NAVServiceUser, $secpasswd)

##Creating NST
New-NAVServerInstance $NAVServiceInstance -DatabaseName $DatabaseName `
                                          -DatabaseServer $DatabaseServer `
                                          -ManagementServicesPort 7045 `
                                          -ClientServicesPort 7046 `
                                          -ODataServicesPort 7048 `
                                          -SOAPServicesPort 7047 `
                                          -ServiceAccount user `
                                          -ServiceAccountCredential $mycreds `
                                          -Verbose

Set-NAVServerConfiguration   -ServerInstance $NAVServiceInstance `
                             -KeyName ServicesDefaultTimeZone `
                             -KeyValue $DefaultTimeZone `
                             -WarningAction SilentlyContinue

Set-NAVServerConfiguration   -ServerInstance $NAVServiceInstance `
                             -KeyName ClientServicesMaxUploadSize `
                             -KeyValue $MaxUploadSize `
                             -WarningAction SilentlyContinue

Set-NAVServerConfiguration   -ServerInstance $NAVServiceInstance `
                             -KeyName EnableTaskScheduler `
                             -KeyValue $EnableTaskScheduler `
                             -WarningAction SilentlyContinue

Set-NAVServerConfiguration   -ServerInstance $NAVServiceInstance `
                             -KeyName ServicesUseNTLMAuthentication `
                             -KeyValue $UseNTLM `
                             -WarningAction SilentlyContinue

Set-NAVServerConfiguration   -ServerInstance $NAVServiceInstance `
                             -KeyName SOAPServicesMaxMsgSize `
                             -KeyValue $SOAPMaxMsgSize `
                             -WarningAction SilentlyContinue
                             
                             
##Creating NAS
IF ($IsNAS) {  
Set-NAVServerConfiguration   -ServerInstance $NAVServiceInstance `
                             -KeyName ClientServicesEnabled `
                             -KeyValue FALSE `
                             -WarningAction SilentlyContinue

Set-NAVServerConfiguration   -ServerInstance $NAVServiceInstance `
                             -KeyName SOAPServicesEnabled `
                             -KeyValue FALSE `
                             -WarningAction SilentlyContinue

Set-NAVServerConfiguration   -ServerInstance $NAVServiceInstance `
                             -KeyName ODataServicesEnabled `
                             -KeyValue FALSE `
                             -WarningAction SilentlyContinue

Set-NAVServerConfiguration   -ServerInstance $NAVServiceInstance `
                             -KeyName ManagementServicesEnabled `
                             -KeyValue FALSE `
                             -WarningAction SilentlyContinue

Set-NAVServerConfiguration   -ServerInstance $NAVServiceInstance `
                             -KeyName NASServicesStartupArgument `
                             -KeyValue $NASArgument `
                             -WarningAction SilentlyContinue

Set-NAVServerConfiguration   -ServerInstance $NAVServiceInstance `
                             -KeyName NASServicesStartupCodeunit `
                             -KeyValue $NASCodeunit `
                             -WarningAction SilentlyContinue

Set-NAVServerConfiguration   -ServerInstance $NAVServiceInstance `
                             -KeyName NASServicesStartupMethod `
                             -KeyValue $NASMethod `
                             -WarningAction SilentlyContinue

Set-NAVServerConfiguration   -ServerInstance $NAVServiceInstance `
                             -KeyName ServicesDefaultCompany `
                             -KeyValue $DefaultCompany `
                             -WarningAction SilentlyContinue
}

##Set Idle Client Timeout
IF ($ChangeTimeout) {  
Set-NAVServerConfiguration   -ServerInstance $NAVServiceInstance `
                             -KeyName ClientServicesIdleClientTimeout `
                             -KeyValue $IdleClientTimeout `
                             -WarningAction SilentlyContinue
}

##Set Services Language
IF ($IsNOR) {  
Set-NAVServerConfiguration   -ServerInstance $NAVServiceInstance `
                             -KeyName DefaultLanguageId `
                             -KeyValue $LanguageID `
                             -WarningAction SilentlyContinue

Set-NAVServerConfiguration   -ServerInstance $NAVServiceInstance `
                             -KeyName ServicesLanguage `
                             -KeyValue $Language `
                             -WarningAction SilentlyContinue
}

#Add NAVService to portsharing and start Service.
#Import-Module $PSScriptRoot\NAVServerInstancePortSharing.ps1
#Enable-NAVServerInstancePortSharing $NAVServiceInstance

 

Synching Microsoft NPS (RADIUS) servers

source: http://www.routereflector.com/2016/07/syncing-microsoft-nps-servers/

Use the following powershell script to sync microsoft NPS (radius) servers.

Export-NpsConfiguration -Path C:\TEMP\LocalNPSExportedConfig.xml

$CurrentServerNPS = $env:computername

$NPServers = Get-ADGroupMember "RAS and IAS Servers"
$NPServers | ForEach-Object {

	$NPServerName = $_.Name

	if ($NPServerName -ne $CurrentServerNPS) {
		$NPServerName
		copy-item Export-NpsConfiguration -Path  \\$NPServerName\C$\TEMP\LocalNPSExportedConfig.xml
		Invoke-Command -ComputerName $NPServerName -ScriptBlock {Export-NPSConfiguration -Path C:\TEMP\BackupNPSExportedConfig.xml
		Invoke-Command -ComputerName $NPServerName -ScriptBlock {Import-NPSConfiguration -Path C:\TEMP\LocalNPSExportedConfig.xml
	}
}

 

Copy SQL server database role

source: http://stackoverflow.com/questions/6300740/how-to-script-sql-server-database-role

 

With the following script a script is generated which can be used to copy a SQL database role

declare @RoleName varchar(50) = 'RoleName'

declare @Script varchar(max) = 'CREATE ROLE ' + @RoleName + char(13)
select @script = @script + 'GRANT ' + prm.permission_name + ' ON ' + OBJECT_NAME(major_id) + ' TO ' + rol.name + char(13) COLLATE Latin1_General_CI_AS 
from sys.database_permissions prm
    join sys.database_principals rol on
        prm.grantee_principal_id = rol.principal_id
where rol.name = @RoleName

print @script

 

VMware get inventory

source: http://www.wooditwork.com/2010/08/16/exporting-all-that-useful-vm-information-with-powercli/

To export a list of usefull information about your environment use the following oneliner to export it to a CSV.

Get-VM | Select Name, PowerState, NumCPU, MemoryMB, ProvisionedSpaceGB, UsedSpaceGB, @{N=”ESX Host”;E={Get-VMHost -VM $_}}, @{N=”Datastore”;E={Get-Datastore -VM $_}}, @{N=”Guest OS”;E={Get-VMGuest -VM $_}} | Export-CSV d:\temp\report.csv

 

 

Copy WSUS approvals between Groups

source: http://www.craig-tolley.co.uk/2016/01/21/wsus-copy-updates-between-groups/

Run the script below, then call it using the following syntax:

Copy-WsusGroupApprovals -WsusServerFqdn wsus.domain.co.uk -SourceGroupName "OldServers" -TargetGroupName "NewServers"

You can optionally specify a port, the default being 8530. You can also specify to use a secure connection. The group names are both case sensitive though.

# ----------------------------------------------------------------------------------------------------------
# PURPOSE:    WSUS - Copy Approvals from one Group to another Group
#
# VERSION     DATE         USER                DETAILS
# 1           21/01/2016   Craig Tolley        First Version
#
# ----------------------------------------------------------------------------------------------------------

#.SYNOPSIS
# Copies all approvals from the specified source group to the specified destination group. 
# Group names are case sensitive. 
# Unless specified the default WSUS port of 8530 will be used to connect. 
function Copy-WsusGroupApprovals
{
    param
    (

    [Parameter(Mandatory=$true)]
    [ValidateNotNullOrEmpty()]
    [String]$WsusServerFqdn,

    [Int]$WsusServerPort = 8530,

    [Boolean]$WsusServerSecureConnect = $false,

    [Parameter(Mandatory=$true)]
    [ValidateNotNullOrEmpty()]
    [String]$SourceGroupName,

    [Parameter(Mandatory=$true)]
    [ValidateNotNullOrEmpty()]
    [String]$TargetGroupName

    )
    
    # Load the assembly required
    try
    {
        [void][reflection.assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration")
    }
    catch
    {
        Write-Error "Unable to load the Microsoft.UpdateServices.Administration assembly: $($_.Exception.Message)"
        break

    }

    # Attempt the connection to the WSUS Server
    try
    {
        $WsusServer = [Microsoft.UpdateServices.Administration.AdminProxy]::getUpdateServer($WsusServerFqdn, $WsusServerSecureConnect, $WsusServerPort)
    }
    catch
    {
        Write-Error "Unable to connect to the WSUS Server: $($_.Exception.Message)"
        break
    }

    # Get all of the Wsus Groups, and check that the specified source and destination groups exist
    $Groups = $WsusServer.GetComputerTargetGroups()
    If ($Groups.Name -notcontains $SourceGroupName -or $Groups.Name -notcontains $TargetGroupName)
    {
        Write-Error "Source or Destination group names cannot be found in the list of groups on the WSUS Server. Group names are case sensitive. Please check your names."
        break
    }
    $SourceGroupObj = $Groups | Where {$_.Name -eq $SourceGroupName}
    $TargetGroupObj = $Groups | Where {$_.Name -eq $TargetGroupName}

    # Get all of the updates on the server
    Write-Progress -Activity "Getting Details of all updates"
    $Updates = $WsusServer.GetUpdates()
    
    # Go through each of the updates. If the update has an approval for the source group, then create an approval for the destination group. 
    $i = 0
    $Approved = 0
    ForEach ($Update in $Updates)
    {
        $i ++
        Write-Progress -Activity "Copying update approvals" -PercentComplete (($i/$($Updates.Count))*100) -Status "$i of $($Updates.Count)"
        
        if ($Update.GetUpdateApprovals($SourceGroupObj).Count -ne 0 -and $Update.GetUpdateApprovals($TargetGroupObj).Count -eq 0)
        {
            Write-Host ("Approving {0} for {1}" -f $Update.Title, $TargetGroupObj.Name)
            $Update.Approve('Install',$TargetGroupObj) | Out-Null
            $Approved ++
        }
    }
    Write-Progress -Activity "Copying update approvals" -Completed

   Write-Output ("Approved {0} updates for target group {1}" -f $Approved, $TargetGroupName)
}

Enable CBT on VMware

See also http://www.bvanleeuwen.nl/faq/?p=1236

Create vm list

$targets = Get-VM | Select Name, @{N="CBT";E={(Get-View $_).Config.ChangeTrackingEnabled}} | WHERE {$_.CBT -like "False"}

Enable CBT

ForEach ($target in $targets) {
   $vm = $target.Name
   $vmView = Get-vm $vm | get-view
   $vmConfigSpec = New-Object VMware.Vim.VirtualMachineConfigSpec
   $vmConfigSpec.changeTrackingEnabled = $true
   $vmView.reconfigVM($vmConfigSpec)
}

Create/Remove snapshot to enable CBT

ForEach ($target in $targets) {
   $vm = $target.Name
   Get-VM $vm | Get-Snapshot | Remove-Snapshot -confirm:$false
   New-Snapshot -VM (Get-VM $vm ) -Name "CBTSnap"
   Get-VM $vm | Get-Snapshot -Name "CBTSnap" | Remove-Snapshot -confirm:$false
}