Last Login from all Domain Controllers

Requires Active Directory Module. Just cut and paste into PowerShell then run the command as shown in the example.

function Get-ADUserLastLogon([string]$userName) {
    $dcs = Get-ADDomainController -Filter {Name -like "*"}
    $time = 0
    foreach($dc in $dcs) {
        $hostname = $dc.HostName
        $user = Get-ADUser $userName -Server $hostname -Properties lastLogon 
        if($user.LastLogon -gt $time) 
            $time = $user.LastLogon
    $dt = [DateTime]::FromFileTime($time)
    "$username last logged on at: $($dt.ToString("yyyy/MM/dd HH:mm:ss"))"


    Get-ADUserLastLogon -UserName JoeBloggs

Additional configurations,
if you wish to exclude specific domain controllers due to communication limitations such as all DCs with DMZ in their name change line two to,

    $dcs = Get-ADDomainController -Filter {Name -notlike "*DMZ*"}

Export list of subnets from Active Directory Sites and Services

Save the following code,

$Sites = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest().Sites
foreach ($Site in $Sites) {
   foreach ($subnet in $site.Subnets) {
      $subnet | Select Name,Site

to ‘ExportSites.ps1’ and run the command,

.\ExportSites.ps1 | Export-CSV sites.txt

Migrate FSRM Quotas using PowerShell to 2012 R2

This version has been superseded by this one

Hello to all of you,

I have been tasked with migrating from one file server solution to another with share folders going to various different locations and roughly 200,000 assigned quotas. The current system is 2008 R2 while the new one is 2012 R2. My plan is to utilise the dirquota.exe command to export the current configuration and then auto generate the required PowerShell commands to import on to the new 2012 R2. Almost all of the quotas we have are basic auto assigned quotas that still match the quota template and these quotas do not need to be individually set but naturally there are the odd quotas that has been modified manually with their own custom email thresholds and limits.

This script has the following assumptions,
1) The quota templates needed to be applied have been migrated to the new server. This is a native command using dirquota.exe template export /File:PATH
2) All Auto Quotas are using templates that match. Probably wouldn’t be much work to make it work with other setups but I am pretty confident that most admins should have set up their auto quotas in this way.
3) Commands are set with a KillTimeOut of 10 minutes. dirquota.exe is not able to output the KillTimeOut value. You can change this manually in either the script or the output.
4) dirquota.exe does not output if the Report ‘Files By Property’ so due to this it is assumed that this report is ticked on for all instances of report actions.
5) Auto Quotas with notifications will probably cause errors with this script.

I believe this is now a working product. Still some more testing to go and to look at ways to improve the code.

** Drop me a line if you find any errors and I will work on updating the code **

List of work to do
– Currently the output includes notifications for all quotas that do not match the template even if their notifications have not been modified. Might be too much work to prevent it. ** BUG: if auto quotas have notifications this will not work as it will try to add notifications that already exist **

# Written by Ben Penney # Version 0.95 # This script has been written to be run on the old/source FSRM server and the output generated to be executed on the target server. # This script has been tested on 2008 R2 and 2012 R2 source servers and 2012 R2 target servers. # SourcePath is the local path on the old server of the folder you want to export the quotas from. # TargetPath is the local path on the new server where you will execute the generated PowerShell commands # Example: # .\ExportQuotas -SourcePath "O:\StaffShared" -TargetPath "C:\TEST" > ImportQuotas.ps1 Param([Parameter(Mandatory = $true)] $SourcePath,$TargetPath) # ---------- START: Process Auto Quotas ---------- # This process is used to generate the PowerShell commands to create the Auto Quotas on the new server. # Additionally the list of auto quotas are kept for comparison later to exclude all quotas that will # be automatically generated from the output of this script. $AutoQuotas = @() $AutoQuotaTemplates = @() ForEach ($line in ((dirquota autoquota list /path:$SourcePath\*) + (dirquota autoquota list /path:$SourcePath\))) { If ($line -like 'Auto Apply Quota Path:*') {$AutoQuotas = $AutoQuotas + $line.Substring(24,$line.Length-24)} If ($line -like 'Source Template:*') { If ($line -like '*(Matches template)') { $AutoQuotaTemplates = $AutoQuotaTemplates + $line.Substring(24,$line.Length-43) "New-FsrmAutoQuota -Path '$($AutoQuotas[-1] -iReplace(($SourcePath -replace "\\","\\"),$TargetPath))' –Template '$($AutoQuotaTemplates[-1])'" } Else {Write-Error "Expecting all autoquotas to be using matching templates. Sorry. Quitting now."} } } If ($AutoQuotas.Length -ne $AutoQuotaTemplates.Length) {Write-Error "Something went wrong with parsing the auto quotas"} # ----------- END: Process Auto Quotas ----------- "Start-Sleep -s 30 # This line is to give the server time to create the auto quotas" Function processDirQuotaOutput ($QuotaOutput) { [int]$LineNum = 2 If ($QuotaOutput[1] -like 'This tool is deprecated*') {$LineNum += 2} # For 2012 output While ($LineNum -lt $QuotaOutput.Length) { # ---------- Quota Path Line ---------- $QuotaPath = $QuotaOutput[$LineNum].Substring(24,$QuotaOutput[$LineNum].Length-24) $QuotaPathNew = $($QuotaPath -iReplace(($SourcePath -replace "\\","\\"),$TargetPath)) $QuotaPathParent = $QuotaPath.SubString(0,$QuotaPath.LastIndexOf("\")) $LineNum++ # ---------- Share Path (2008) or Description (2012) Line ---------- # Skipped $LineNum++ # ---------- Source Template Line ---------- If ($QuotaOutput[$LineNum] -like '*(Does not match template)') { $SourceTemplateMatches = $false $SourceTemplate = $QuotaOutput[$LineNum].Substring(24,$QuotaOutput[$LineNum].Length-50) } ElseIf ($QuotaOutput[$LineNum] -like '*(Matches template)') { $SourceTemplateMatches = $true $SourceTemplate = $QuotaOutput[$LineNum].Substring(24,$QuotaOutput[$LineNum].Length-43) } $LineNum++ # ---------- Quota Status Line ---------- If ($QuotaOutput[$LineNum] -like '*Disabled') {$QuotaStatus = "-Disabled "} $LineNum++ # ---------- Limit Line ---------- $Limit = $QuotaOutput[$LineNum].Substring(24,$QuotaOutput[$LineNum].Length-31).Replace(' ','') If ($QuotaOutput[$LineNum].Substring($QuotaOutput[$LineNum].Length-5,4) -eq 'Soft') { $LimitType = "-SoftLimit" } $LineNum++ # ---------- Used, Available, Peak Usage Line ---------- # Skipped $LineNum += 3 # ---------- START: Generate Quota commands ---------- # Since this is the fisrt variable output by the dirquota.exe command we need to create a command # for the previous quota read in from the file if there was one. $ProcessNotifications = $false If ($AutoQuotas -contains $QuotaPathParent) { # Quota is the child of an auto quota so will have a template set (assuming all auto quotas are templates) If ($SourceTemplate -eq $Null) { # Quota has no template so should be removed (assuming all auto quotas are templates) "Remove-FsrmQuota -Path '$QuotaPathNew' -Confirm:`$False" "New-FsrmQuota -Path '$QuotaPathNew' -Size $Limit $LimitType $QuotaStatus" $ProcessNotifications = $true } ElseIf ($SourceTemplate -ne $AutoQuotaTemplates[[array]::indexof($AutoQuotas,$QuotaPathParent)]) { # Quota does not match template of auto quota "Reset-FsrmQuota -Path '$QuotaPathNew' -Template '$SourceTemplate' -Confirm:`$False" $ProcessNotifications = $true } } Else { # Quota is not the child of auto quota so will not have any quota yet If ($SourceTemplate -eq $Null) { "New-FsrmQuota -Path '$QuotaPathNew' -Size $Limit $LimitType $QuotaStatus" $ProcessNotifications = $true } Else { "New-FsrmQuota -Path '$QuotaPathNew' -Template '$SourceTemplate'" $ProcessNotifications = $true } } If ($SourceTemplateMatches -eq $False) { # Quota is a template but does not match so update the changes "Set-FsrmQuota -Path '$QuotaPathNew' -Size $Limit $LimitType $QuotaStatus" $ProcessNotifications = $true } # ----------- END: Generate Quota commands ----------- # ---------- Thresholds Line ---------- $LineNum += 2 If ($QuotaOutput[$LineNum-2] -notlike '*None' -And $ProcessNotifications) { $Thresholds = "" While ($LineNum -lt $QuotaOutput.Length -And ` $QuotaOutput[$LineNum] -notlike 'Quota Path:*') { $Actions = "" [int]$NotificationLimit = $QuotaOutput[$LineNum].SubString($QuotaOutput[$LineNum].IndexOf("(")+1,3).Trim() $LineNum += 2 While ($LineNum -lt $QuotaOutput.Length -And ` $QuotaOutput[$LineNum] -notlike 'Quota Path:*' -And ` $QuotaOutput[$LineNum] -notlike 'Notifications for *') { $NotificationType = $QuotaOutput[$LineNum].SubString(32,$QuotaOutput[$LineNum].Length-32) Switch ($NotificationType) { 'Event Log' { [int]$RunLimitInterval = $QuotaOutput[$LineNum+1].SubString(32,$QuotaOutput[$LineNum+1].Length-39) $EventType = $QuotaOutput[$LineNum+2].SubString(32,$QuotaOutput[$LineNum+2].Length-32) $MessageBody = $QuotaOutput[$LineNum+3].SubString(32,$QuotaOutput[$LineNum+3].Length-32) $LineNum += 5 While ($LineNum -lt $QuotaOutput.Length -And ` $QuotaOutput[$LineNum] -notlike 'Quota Path:*' -And ` $QuotaOutput[$LineNum] -notlike '*Notification Type:*' -And ` $QuotaOutput[$LineNum] -notlike 'Notifications for *') { $MessageBody += "`r`n" + $QuotaOutput[$LineNum-1] $LineNum++ } $Actions += ",(New-FsrmAction Event -EventType $EventType -Body '$MessageBody')" } 'E-mail' { [int]$RunLimitInterval = $QuotaOutput[$LineNum+1].SubString(32,$QuotaOutput[$LineNum+1].Length-39) $MailTo = $QuotaOutput[$LineNum+2].SubString(32,$QuotaOutput[$LineNum+2].Length-32) $LineNum += 3 $MailSubject = "" If ($QuotaOutput[$LineNum] -like '*Mail Subject:*') { $MailSubject = $QuotaOutput[$LineNum].SubString(32,$QuotaOutput[$LineNum].Length-32) $LineNum++ } $MessageBody = $QuotaOutput[$LineNum].SubString(32,$QuotaOutput[$LineNum].Length-32) $LineNum += 2 While ($LineNum -lt $QuotaOutput.Length -And ` $QuotaOutput[$LineNum] -notlike 'Quota Path:*' -And ` $QuotaOutput[$LineNum] -notlike '*Notification Type:*' -And ` $QuotaOutput[$LineNum] -notlike 'Notifications for *') { $MessageBody += "`r`n" + $QuotaOutput[$LineNum-1] $LineNum++ } $Actions += ",(New-FsrmAction Email -MailTo '$MailTo' -Subject '$MailSubject' -Body '$MessageBody'" $Actions += " -RunLimitInterval $RunLimitInterval)" } 'Command' { [int]$RunLimitInterval = $QuotaOutput[$LineNum+1].SubString(32,$QuotaOutput[$LineNum+1].Length-39) $Command = $QuotaOutput[$LineNum+2].SubString(32,$QuotaOutput[$LineNum+2].Length-32) $Arguments = $QuotaOutput[$LineNum+3].SubString(32,$QuotaOutput[$LineNum+3].Length-32) $WorkingDirectory = $QuotaOutput[$LineNum+4].SubString(32,$QuotaOutput[$LineNum+4].Length-32) Switch ($QuotaOutput[$LineNum+5].SubString(32,$QuotaOutput[$LineNum+5].Length-32)) { 'NT AUTHORITY\LOCAL SERVICE' {$RunAs = 'LocalService'} 'NT AUTHORITY\SYSTEM' {$RunAs = 'LocalSystem'} 'NT AUTHORITY\NETWORK SERVICE' {$RunAs = 'NetworkService'} } $LineNum += 7 $Actions += ",(New-FsrmAction Command -Command '$Command' -CommandParameters '$Arguments' -WorkingDirectory '$WorkingDirectory'" $Actions += " -SecurityLevel $RunAs -RunLimitInterval $RunLimitInterval -Killtimeout 10)" } 'Report' { #---Do nothing for now--- [int]$RunLimitInterval = $QuotaOutput[$LineNum+1].SubString(32,$QuotaOutput[$LineNum+1].Length-39) $LineNum += 2 $Reports = "FilesByProperty" While ($QuotaOutput[$LineNum] -notlike '*Reports saved to:*') { Switch ($QuotaOutput[$LineNum].SubString(6,10)) { 'Duplicate ' {$Reports += ",DuplicateFiles"} 'File Scree' {$Reports += ",FileScreen"} 'Files by F' {$Reports += ",FilesByFileGroup"} 'Files by O' {$Reports += ",FilesByOwner"} 'Large File' {$Reports += ",LargeFiles"} 'Least Rece' {$Reports += ",LeastRecentlyAccessed"} 'Most Recen' {$Reports += ",MostRecentlyAccessed"} 'Quota Usag' {$Reports += ",QuotaUsage"} } $LineNum++ } $SendReportsTo = "" If ($QuotaOutput[$LineNum+1].Length -gt 32) { $SendReportsTo = $QuotaOutput[$LineNum+1].SubString(32,$QuotaOutput[$LineNum+1].Length-32) } $LineNum += 3 $Actions += ",(New-FsrmAction Report -ReportTypes $Reports -MailTo '$SendReportsTo')" } } } $Thresholds += ",(New-FsrmQuotaThreshold -Percentage $NotificationLimit -Action $($Actions.SubString(1)))" } "Set-FsrmQuota -Path '$QuotaPathNew' -Threshold $($Thresholds.SubString(1))" } # ----------- END: Generate Threshold commands ----------- # ---------- START: Reset variables ---------- $QuotaPath = $null $QuotaPathNew = $null $QuotaPathParent = $null $SourceTemplate = $null $SourceTemplateMatches = $null $QuotaStatus = $null $Limit = $null $LimitType = $null $Thresholds = @() # ----------- END: Reset variables ----------- } } # ---------- START: Process Quotas ---------- processDirQuotaOutput (dirquota quota list /path:$SourcePath\* -List-Notifications) processDirQuotaOutput (dirquota quota list /path:$SourcePath\ -List-Notifications) # ----------- END: Process Quotas -----------