Skip to content

Instantly share code, notes, and snippets.

@laymanstake
Last active March 8, 2024 16:54
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save laymanstake/4a16bdda8c7ad94c5bdfe734892dcf4e to your computer and use it in GitHub Desktop.
Save laymanstake/4a16bdda8c7ad94c5bdfe734892dcf4e to your computer and use it in GitHub Desktop.
This function creates DFS inventory for the given domain. It uses PS jobs to process multiple DFS shares in parallel so report should be available within mins
Import-module ActiveDirectory
if ((Get-Module -ListAvailable -Name DFSN) -AND (Get-Module -ListAvailable -Name DFSR)) {
Import-Module DFSN
Import-Module DFSR
}
else {
Exit
Write-Output "Either of DFSN or DFSR is not available"
}
$logpath = "$env:USERPROFILE\desktop\ADReport_$(get-date -Uformat "%Y%m%d-%H%M%S").txt"
# This function creates log entries for the major steps in the script.
function Write-Log {
[CmdletBinding()]
Param(
[Parameter(ValueFromPipeline = $true, mandatory = $true)]$logtext,
[Parameter(ValueFromPipeline = $true, mandatory = $true)]$logpath
)
$Stamp = (Get-Date).toString("yyyy/MM/dd HH:mm:ss")
$LogMessage = "$Stamp : $logtext"
$isWritten = $false
do {
try {
Add-content $logpath -value $LogMessage -Force -ErrorAction SilentlyContinue
$isWritten = $true
}
catch {
}
} until ( $isWritten )
}
# This function creates DFS inventory for the given domain.
function Get-DFSInventory {
param (
[Parameter(ValueFromPipeline = $true, mandatory = $true)]$DomainName,
[Parameter(ValueFromPipeline = $true, mandatory = $true)][pscredential]$Credential
)
$PDC = (Test-Connection -Computername (Get-ADDomainController -Filter * -Server $DomainName -Credential $Credential).Hostname -count 1 -AsJob | Get-Job | Receive-Job -Wait | Where-Object { $null -ne $_.Responsetime } | sort-object Responsetime | select-Object Address -first 1).Address
$null = Get-Job | Remove-Job
$ReplicatedFolders = Get-DfsReplicatedFolder -DomainName $DomainName -ErrorAction SilentlyContinue | Select-Object DFSNPath, GroupName -Unique
$HoursReplicated = Get-DfsrGroupSchedule -DomainName $DomainName -ErrorAction SilentlyContinue | Select-Object GroupName, HoursReplicated
$Members = Get-DfsrMembership -DomainName $Domainname -ErrorAction SilentlyContinue | Select-Object GroupName, ReadOnly, RemoveDeletedFiles, Enabled, State
$infoObject = @()
$DFSDetails = @()
$maxParallelJobs = 50
$jobs = @()
$Namespaces = Get-ADObject -Filter "Objectclass -eq 'msDFS-LinkV2'" -Server $PDC -Credential $Credential -Properties "msDFS-LinkPAthv2", CanonicalName | Select-Object @{l = "DFSNRoot"; e = { "\\" + ($_.CanonicalName.split("/\"))[0] + "\" + ($_.CanonicalName.split("/\"))[3] } }, @{l = "NameSpacePath"; e = { "\\" + ($_.CanonicalName.split("/\"))[0] + "\" + ($_.CanonicalName.split("/\"))[3] + $_.("MSDFS-LinkPATHV2").Replace("/", "\") } }
Write-Log -logtext "$($Namespaces.count) DFS shares found in $DomainName. Looking into further details" -logpath $logpath
if ($Namespaces) {
$Namespaces | ForEach-Object {
while ((Get-Job -State Running).Count -ge $maxParallelJobs) {
Start-Sleep -Milliseconds 500 # Wait for 0.5 seconds before checking again
}
$ScriptBlock = {
param($namespace, $DomainName, $ReplicatedFolders, $HoursReplicated, $Members)
$namespacePath = $Namespace.Namespacepath
try {
$Shares = Get-DFSNFolderTarget -Path $namespacePath -ErrorAction SilentlyContinue
}
catch {
$Shares = $null
}
If ($Shares) {
$ShareNames = ($Shares | Select-Object TargetPath).TargetPath
$ContentPath = @()
$ContentPath += $ShareNames | ForEach-Object {
$Share = $_
$ShareName = ($Share.Split('\\') | select-Object -Last 1)
$ServerName = ($Share.split("\\")[2])
If (-Not($ServerName -match "[.]")) {
$ServerName = $ServerName + "." + $DomainName
}
if (Test-Connection -ComputerName $ServerName -count 1 -Quiet ) {
try {
$Path = Get-WmiObject Win32_Share -filter "Name LIKE '$Sharename'" -ComputerName $ServerName -ErrorAction SilentlyContinue
}
catch {
Write-Output $_.Exception.Message
}
}
if ($Path) {
"$($ServerName)::$($Path.Path)"
}
else {
"$($ServerName) not reachable"
}
}
$RGGroup = ($ReplicatedFolders | Where-Object { $_.DFSNPath -eq $namespacePath -AND $_.DFSNPath -ne "" }).Groupname
if ($RGGroup) {
$RGHoursReplicated = ($HoursReplicated | Where-Object { $_.GroupName -eq $RGGroup } | Select-Object HoursReplicated).HoursReplicated
$RGMembers = $Members | Where-Object { $_.GroupName -eq $RGGroup } | Select-Object ReadOnly, RemoveDeletedFiles, Enabled, State
}
else {
$RGGroup = "No replication group found"
$RGHoursReplicated = "NA"
$RGMembers = "NA"
}
$NamespaceDetails = [PSCustomObject]@{
DFSNRoot = $namespace.DFSNRoot
NamespacePath = $NameSpacePath
RGGroup = $RGGroup
ShareNames = $ShareNames
ContentPath = $ContentPath
RGMembers = $RGMembers
RGHoursReplicated = $RGHoursReplicated
}
Return $NamespaceDetails
}
}
$jobs += Start-Job -ScriptBlock $scriptBlock -ArgumentList $_ , $DomainName, $ReplicatedFolders, $HoursReplicated, $Members
}
Write-Log -logtext "Powershell jobs submitted for looking into $($Namespaces.count) DFS shares details in $DomainName" -logpath $logpath
$null = $jobs | Wait-Job
$result = @()
foreach ($job in $jobs) {
$result += Receive-Job -Job $job
}
$null = Get-Job | remove-Job
Write-Log -logtext "Powershell jobs completed for $($Namespaces.count) DFS shares details in $DomainName" -logpath $logpath
ForEach ($res in $result) {
$infoObject += [PSCustomObject]@{
DFSNRoot = $res.DFSNRoot
NamespacePath = $res.NameSpacePath
ReplicationGroupName = $res.RGGroup
ShareNames = $res.ShareNames -join "`n"
ContentPath = $res.ContentPath -join "`n"
ReadOnly = $res.RGMembers.readOnly -join "`n"
RemoveDeletedFiles = $res.RGMembers.RemoveDeletedFiles -join "`n"
Enabled = $res.RGMembers.Enabled -join "`n"
HoursReplicated = $res.RGHoursReplicated
State = $res.RGMembers.State -join "`n"
}
}
}
$RGGroupDetails = Get-DfsrMembership -DomainName $DomainName | Select-Object GroupName, Computername, FolderName, ContentPath, ReadOnly, State
$DFSDetails += [PSCustomObject]@{
NameSpace = $infoObject
ReplicationGroup = $RGGroupDetails
}
Return $DFSDetails
}
$Report = Get-DFSInventory -DomainName $env:USERDNSDOMAIN -credential (get-credential)
$Report.NameSpace | Export-csv -nti c:\temp\Namespacereport.csv
$Report.ReplicationGroup | Export-csv -nti c:\temp\ReplicationGroupReport.csv
@nik02150
Copy link

Hello

Thanks for writing this script. I'm testing your script and ran into an error with write-log function. The function is not included in this script. So, I couldn't get it to work.

@laymanstake
Copy link
Author

Hello

Thanks for writing this script. I'm testing your script and ran into an error with write-log function. The function is not included in this script. So, I couldn't get it to work.

Sorry for the same. I have added the function now

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment