Update Workflows/Windows/Windows Server/Roles/DFS/Creating and Configuring DFS Namespaces with Replication.md
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				GitOps Automatic Deployment / GitOps Automatic Deployment (push) Successful in 8s
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	GitOps Automatic Deployment / GitOps Automatic Deployment (push) Successful in 8s
				
			This commit is contained in:
		| @@ -124,263 +124,266 @@ In the Replication wizard that appears after about a minute, you can configure t | |||||||
| ### Checking DFS Status | ### Checking DFS Status | ||||||
| You may want to put together a simple table report of the DFS namespaces, replication info, and target folders.  You can run the following powershell script to generate a nice table-based report of the current structure of the DFS namespaces in your domain. | You may want to put together a simple table report of the DFS namespaces, replication info, and target folders.  You can run the following powershell script to generate a nice table-based report of the current structure of the DFS namespaces in your domain. | ||||||
|  |  | ||||||
| ```powershell | ??? example "Powershell Reporting Script" | ||||||
| [CmdletBinding()] |     ```powershell | ||||||
| param( |     # Automatically detect current AD domain and use it as DFS prefix | ||||||
|   [string]$DomainPrefix = "\\bunny-lab.io"  # Adjust if Different |     try { | ||||||
| ) |         $Domain = ([System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()).Name | ||||||
|  |         $DomainPrefix = "\\$Domain" | ||||||
| Import-Module DFSN -ErrorAction Stop |     } catch { | ||||||
| Import-Module DFSR -ErrorAction Stop |         Write-Warning "Unable to detect domain automatically. Falling back to manual value." | ||||||
|  |         $DomainPrefix = "\\bunny-lab.io" | ||||||
| function Get-ServerNameFromPath { |  | ||||||
|   param([string]$Path) |  | ||||||
|   if ([string]::IsNullOrWhiteSpace($Path)) { return $null } |  | ||||||
|   if ($Path -like "\\*") { return ($Path -split '\\')[2] } |  | ||||||
|   return $null |  | ||||||
| } |  | ||||||
| function Get-Max3 { |  | ||||||
|   param([int[]]$Values) |  | ||||||
|   if (-not $Values) { return 0 } |  | ||||||
|   return (($Values | Measure-Object -Maximum).Maximum) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| # Build: GroupName (lower) -> memberships[] |  | ||||||
| $allGroups = Get-DfsReplicationGroup -ErrorAction SilentlyContinue |  | ||||||
| $groupMembershipMap = @{} |  | ||||||
| foreach ($g in $allGroups) { |  | ||||||
|   $ms = Get-DfsrMembership -GroupName $g.GroupName -ErrorAction SilentlyContinue |  | ||||||
|   $groupMembershipMap[$g.GroupName.ToLower()] = $ms |  | ||||||
| } |  | ||||||
|  |  | ||||||
| # Flatten all memberships for regex fallback |  | ||||||
| $allMemberships = @() |  | ||||||
| foreach ($arr in $groupMembershipMap.Values) { if ($arr) { $allMemberships += $arr } } |  | ||||||
|  |  | ||||||
| $rows = New-Object System.Collections.Generic.List[psobject] |  | ||||||
|  |  | ||||||
| # Enumerate namespace roots |  | ||||||
| $roots = Get-DfsnRoot -ErrorAction Stop | Where-Object { $_.Path -like "$DomainPrefix\*" } |  | ||||||
|  |  | ||||||
| Write-Host "DFS Namespace and Replication Overview" -ForegroundColor Cyan |  | ||||||
| Write-Host "------------------------------------------------------`n" |  | ||||||
|  |  | ||||||
| foreach ($root in $roots) { |  | ||||||
|  |  | ||||||
|   $rootPath  = $root.Path |  | ||||||
|   $rootLeaf  = ($rootPath -split '\\')[-1] |  | ||||||
|  |  | ||||||
|   $nsServers = @() |  | ||||||
|   $rootTargets = Get-DfsnRootTarget -Path $rootPath -ErrorAction SilentlyContinue |  | ||||||
|   foreach ($rt in $rootTargets) { |  | ||||||
|     $srv = Get-ServerNameFromPath $rt.TargetPath |  | ||||||
|     if ($srv) { $nsServers += $srv } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   # Folders under this root |  | ||||||
|   $folders = Get-DfsnFolder -Path "$rootPath\*" -ErrorAction SilentlyContinue | Sort-Object Path |  | ||||||
|  |  | ||||||
|   foreach ($f in $folders) { |  | ||||||
|     $namespaceFull = $f.Path |  | ||||||
|     $leaf          = ($f.Path -split '\\')[-1] |  | ||||||
|  |  | ||||||
|     # DFSN folder targets |  | ||||||
|     $targets = Get-DfsnFolderTarget -Path $f.Path -ErrorAction SilentlyContinue |  | ||||||
|     $targets = @($targets | Sort-Object { Get-ServerNameFromPath $_.TargetPath })  # ensure array |  | ||||||
|  |  | ||||||
|     # Map to DFSR group by naming; fallback to regex on ContentPath |  | ||||||
|     $candidateGroup = ((($rootPath -replace '^\\\\','') + '\' + $leaf).ToLower()) |  | ||||||
|     if ($groupMembershipMap.ContainsKey($candidateGroup)) { |  | ||||||
|       $msForFolder = $groupMembershipMap[$candidateGroup] |  | ||||||
|     } else { |  | ||||||
|       $escapedRootLeaf = [regex]::Escape($rootLeaf) |  | ||||||
|       $escapedLeaf     = [regex]::Escape($leaf) |  | ||||||
|       $regex = "\\$escapedRootLeaf\\$escapedLeaf($|\\)" |  | ||||||
|       $msForFolder = $allMemberships | Where-Object { $_.ContentPath -imatch $regex } |  | ||||||
|     } |     } | ||||||
|     $msForFolder = @($msForFolder) # normalize to array |  | ||||||
|  |  | ||||||
|     # Build aligned rows: one per target |     Import-Module DFSN -ErrorAction Stop | ||||||
|     $targetLines = @() |     Import-Module DFSR -ErrorAction Stop | ||||||
|     $replLines   = @() |  | ||||||
|  |  | ||||||
|     foreach ($t in $targets) { |     function Get-ServerNameFromPath { | ||||||
|       $tServer = Get-ServerNameFromPath $t.TargetPath |       param([string]$Path) | ||||||
|       $targetLines += $t.TargetPath |       if ([string]::IsNullOrWhiteSpace($Path)) { return $null } | ||||||
|  |       if ($Path -like "\\*") { return ($Path -split '\\')[2] } | ||||||
|  |       return $null | ||||||
|  |     } | ||||||
|  |     function Get-Max3 { | ||||||
|  |       param([int[]]$Values) | ||||||
|  |       if (-not $Values) { return 0 } | ||||||
|  |       return (($Values | Measure-Object -Maximum).Maximum) | ||||||
|  |     } | ||||||
|  |  | ||||||
|       $msForServer = $null |     # Build: GroupName (lower) -> memberships[] | ||||||
|       if ($msForFolder.Count -gt 0) { |     $allGroups = Get-DfsReplicationGroup -ErrorAction SilentlyContinue | ||||||
|         $msForServer = $msForFolder | Where-Object { $_.ComputerName -ieq $tServer } | Select-Object -First 1 |     $groupMembershipMap = @{} | ||||||
|  |     foreach ($g in $allGroups) { | ||||||
|  |       $ms = Get-DfsrMembership -GroupName $g.GroupName -ErrorAction SilentlyContinue | ||||||
|  |       $groupMembershipMap[$g.GroupName.ToLower()] = $ms | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     # Flatten all memberships for regex fallback | ||||||
|  |     $allMemberships = @() | ||||||
|  |     foreach ($arr in $groupMembershipMap.Values) { if ($arr) { $allMemberships += $arr } } | ||||||
|  |  | ||||||
|  |     $rows = New-Object System.Collections.Generic.List[psobject] | ||||||
|  |  | ||||||
|  |     # Enumerate namespace roots | ||||||
|  |     $roots = Get-DfsnRoot -ErrorAction Stop | Where-Object { $_.Path -like "$DomainPrefix\*" } | ||||||
|  |  | ||||||
|  |     Write-Host "DFS Namespace and Replication Overview" -ForegroundColor Cyan | ||||||
|  |     Write-Host "------------------------------------------------------`n" | ||||||
|  |  | ||||||
|  |     foreach ($root in $roots) { | ||||||
|  |  | ||||||
|  |       $rootPath  = $root.Path | ||||||
|  |       $rootLeaf  = ($rootPath -split '\\')[-1] | ||||||
|  |  | ||||||
|  |       $nsServers = @() | ||||||
|  |       $rootTargets = Get-DfsnRootTarget -Path $rootPath -ErrorAction SilentlyContinue | ||||||
|  |       foreach ($rt in $rootTargets) { | ||||||
|  |         $srv = Get-ServerNameFromPath $rt.TargetPath | ||||||
|  |         if ($srv) { $nsServers += $srv } | ||||||
|       } |       } | ||||||
|       if ($msForServer -and $msForServer.ContentPath) { $replLines += $msForServer.ContentPath } else { $replLines += '' } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     # Max line count for row expansion (PS 5.1 safe) |       # Folders under this root | ||||||
|     $maxLines = Get-Max3 @($targetLines.Count, $replLines.Count, $nsServers.Count) |       $folders = Get-DfsnFolder -Path "$rootPath\*" -ErrorAction SilentlyContinue | Sort-Object Path | ||||||
|  |  | ||||||
|     for ($i = 0; $i -lt $maxLines; $i++) { |       foreach ($f in $folders) { | ||||||
|  |         $namespaceFull = $f.Path | ||||||
|  |         $leaf          = ($f.Path -split '\\')[-1] | ||||||
|  |  | ||||||
|       # Precompute values (PS 5.1: no inline-if in hashtables) |         # DFSN folder targets | ||||||
|       $nsVal = '' |         $targets = Get-DfsnFolderTarget -Path $f.Path -ErrorAction SilentlyContinue | ||||||
|       if ($i -eq 0) { $nsVal = $namespaceFull } |         $targets = @($targets | Sort-Object { Get-ServerNameFromPath $_.TargetPath })  # ensure array | ||||||
|  |  | ||||||
|       $targetVal = '' |         # Map to DFSR group by naming; fallback to regex on ContentPath | ||||||
|       if ($i -lt $targetLines.Count) { $targetVal = $targetLines[$i] } |         $candidateGroup = ((($rootPath -replace '^\\\\','') + '\' + $leaf).ToLower()) | ||||||
|  |         if ($groupMembershipMap.ContainsKey($candidateGroup)) { | ||||||
|  |           $msForFolder = $groupMembershipMap[$candidateGroup] | ||||||
|  |         } else { | ||||||
|  |           $escapedRootLeaf = [regex]::Escape($rootLeaf) | ||||||
|  |           $escapedLeaf     = [regex]::Escape($leaf) | ||||||
|  |           $regex = "\\$escapedRootLeaf\\$escapedLeaf($|\\)" | ||||||
|  |           $msForFolder = $allMemberships | Where-Object { $_.ContentPath -imatch $regex } | ||||||
|  |         } | ||||||
|  |         $msForFolder = @($msForFolder) # normalize to array | ||||||
|  |  | ||||||
|       $replVal = '' |         # Build aligned rows: one per target | ||||||
|       if ($i -lt $replLines.Count) { $replVal = $replLines[$i] } |         $targetLines = @() | ||||||
|  |         $replLines   = @() | ||||||
|  |  | ||||||
|       $nsServerVal = '' |         foreach ($t in $targets) { | ||||||
|       if ($i -lt $nsServers.Count) { $nsServerVal = $nsServers[$i] } |           $tServer = Get-ServerNameFromPath $t.TargetPath | ||||||
|  |           $targetLines += $t.TargetPath | ||||||
|  |  | ||||||
|       $row = [PSCustomObject]@{ |           $msForServer = $null | ||||||
|         'Namespace'               = $nsVal |           if ($msForFolder.Count -gt 0) { | ||||||
|         'Member Folder Target(s)' = $targetVal |             $msForServer = $msForFolder | Where-Object { $_.ComputerName -ieq $tServer } | Select-Object -First 1 | ||||||
|         'Replication Locations'   = $replVal |  | ||||||
|         'Namespace Servers'       = $nsServerVal |  | ||||||
|       } |  | ||||||
|       $rows.Add($row) | Out-Null |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| # Render as a PowerShell table (multi-line cells wrap) |  | ||||||
| #$rows | Format-Table -AutoSize -Wrap |  | ||||||
|  |  | ||||||
| function Write-DfsGrid { |  | ||||||
|   [CmdletBinding()] |  | ||||||
|   param( |  | ||||||
|     [Parameter(Mandatory)] |  | ||||||
|     [System.Collections.IEnumerable]$Data, |  | ||||||
|  |  | ||||||
|     [string[]]$Columns = @('Namespace','Member Folder Target(s)','Replication Locations','Namespace Servers'), |  | ||||||
|  |  | ||||||
|     # Reasonable max widths; tune to your console |  | ||||||
|     [int[]]$MaxWidths = @(50, 60, 50, 28), |  | ||||||
|  |  | ||||||
|     [switch]$Ascii  # use +-| instead of box-drawing if your console garbles Unicode |  | ||||||
|   ) |  | ||||||
|  |  | ||||||
|   # Ensure arrays align |  | ||||||
|   if ($MaxWidths.Count -lt $Columns.Count) { |  | ||||||
|     $pad = New-Object System.Collections.Generic.List[int] |  | ||||||
|     $pad.AddRange($MaxWidths) |  | ||||||
|     for ($i=$MaxWidths.Count; $i -lt $Columns.Count; $i++) { $pad.Add(40) } |  | ||||||
|     $MaxWidths = $pad.ToArray() |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   # Characters |  | ||||||
|   if ($Ascii) { |  | ||||||
|     $H = @{ tl='+'; tr='+'; bl='+'; br='+'; hz='-'; vt='|'; tj='+'; mj='+'; bj='+' } |  | ||||||
|   } else { |  | ||||||
|     # Box-drawing |  | ||||||
|     $H = @{ tl='┌'; tr='┐'; bl='└'; br='┘'; hz='─'; vt='│'; tj='┬'; mj='┼'; bj='┴' } |  | ||||||
|     try { [Console]::OutputEncoding = [Text.UTF8Encoding]::UTF8 } catch {} |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   function TruncPad([string]$s, [int]$w) { |  | ||||||
|     if ($null -eq $s) { $s = '' } |  | ||||||
|     $s = $s -replace '\r','' -replace '\t',' ' |  | ||||||
|     if ($s.Length -le $w) { return $s.PadRight($w, ' ') } |  | ||||||
|     if ($w -le 1) { return $s.Substring(0, $w) } |  | ||||||
|     return ($s.Substring(0, $w-1) + '…') |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   # Materialize and compute widths |  | ||||||
|   $rows = @($Data | ForEach-Object { |  | ||||||
|     # Build a string-only hashtable per row for consistent measurement |  | ||||||
|     $o = @{} |  | ||||||
|     foreach ($c in $Columns) { $o[$c] = [string]($_.$c) } |  | ||||||
|     [pscustomobject]$o |  | ||||||
|   }) |  | ||||||
|  |  | ||||||
|   $widths = @() |  | ||||||
|   for ($i=0; $i -lt $Columns.Count; $i++) { |  | ||||||
|     $col = $Columns[$i] |  | ||||||
|     $max = $col.Length |  | ||||||
|     foreach ($r in $rows) { |  | ||||||
|       $len = ([string]$r.$col).Length |  | ||||||
|       if ($len -gt $max) { $max = $len } |  | ||||||
|     } |  | ||||||
|     $widths += [Math]::Min($max, $MaxWidths[$i]) |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   # Line builders |  | ||||||
|   function DrawTop() { |  | ||||||
|       $line = $H.tl |  | ||||||
|       for ($i = 0; $i -lt $widths.Count; $i++) { |  | ||||||
|           $line += ($H.hz * $widths[$i]) |  | ||||||
|           if ($i -lt ($widths.Count - 1)) { |  | ||||||
|               $line += $H.tj |  | ||||||
|           } else { |  | ||||||
|               $line += $H.tr |  | ||||||
|           } |           } | ||||||
|       } |           if ($msForServer -and $msForServer.ContentPath) { $replLines += $msForServer.ContentPath } else { $replLines += '' } | ||||||
|       $line |         } | ||||||
|   } |  | ||||||
|   function DrawMid() { |         # Max line count for row expansion (PS 5.1 safe) | ||||||
|     $line = $H.vt |         $maxLines = Get-Max3 @($targetLines.Count, $replLines.Count, $nsServers.Count) | ||||||
|     for ($i=0; $i -lt $widths.Count; $i++) { |  | ||||||
|       $line += TruncPad $Columns[$i] $widths[$i] |         for ($i = 0; $i -lt $maxLines; $i++) { | ||||||
|       $line += $H.vt |  | ||||||
|     } |           # Precompute values (PS 5.1: no inline-if in hashtables) | ||||||
|     $line |           $nsVal = '' | ||||||
|   } |           if ($i -eq 0) { $nsVal = $namespaceFull } | ||||||
|   function DrawSep() { |  | ||||||
|     $line = $H.vt |           $targetVal = '' | ||||||
|     for ($i=0; $i -lt $widths.Count; $i++) { |           if ($i -lt $targetLines.Count) { $targetVal = $targetLines[$i] } | ||||||
|       $line += ($H.hz * $widths[$i]) |  | ||||||
|       $line += $H.vt |           $replVal = '' | ||||||
|     } |           if ($i -lt $replLines.Count) { $replVal = $replLines[$i] } | ||||||
|     $line |  | ||||||
|   } |           $nsServerVal = '' | ||||||
|   function DrawHeaderSep() { |           if ($i -lt $nsServers.Count) { $nsServerVal = $nsServers[$i] } | ||||||
|     $line = $H.vt |  | ||||||
|     for ($i=0; $i -lt $widths.Count; $i++) { |           $row = [PSCustomObject]@{ | ||||||
|       $line += ($H.hz * $widths[$i]) |             'Namespace'               = $nsVal | ||||||
|       $line += $H.vt |             'Member Folder Target(s)' = $targetVal | ||||||
|     } |             'Replication Locations'   = $replVal | ||||||
|     $line |             'Namespace Servers'       = $nsServerVal | ||||||
|   } |  | ||||||
|   function DrawBottom() { |  | ||||||
|       $line = $H.bl |  | ||||||
|       for ($i = 0; $i -lt $widths.Count; $i++) { |  | ||||||
|           $line += ($H.hz * $widths[$i]) |  | ||||||
|           if ($i -lt ($widths.Count - 1)) { |  | ||||||
|               $line += $H.bj |  | ||||||
|           } else { |  | ||||||
|               $line += $H.br |  | ||||||
|           } |           } | ||||||
|  |           $rows.Add($row) | Out-Null | ||||||
|  |         } | ||||||
|       } |       } | ||||||
|       $line |  | ||||||
|   } |  | ||||||
|   function DrawRow($r) { |  | ||||||
|     $line = $H.vt |  | ||||||
|     for ($i=0; $i -lt $widths.Count; $i++) { |  | ||||||
|       $val = [string]$r.($Columns[$i]) |  | ||||||
|       $line += TruncPad $val $widths[$i] |  | ||||||
|       $line += $H.vt |  | ||||||
|     } |     } | ||||||
|     $line |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   # Render with group separators between namespaces (when the Namespace cell is non-empty) |     # Render as a PowerShell bordered grid with one-space left/right padding in every cell | ||||||
|   Write-Host (DrawTop) |     function Write-DfsGrid { | ||||||
|   Write-Host (DrawMid) |       [CmdletBinding()] | ||||||
|   Write-Host (DrawHeaderSep) |       param( | ||||||
|  |         [Parameter(Mandatory)] | ||||||
|  |         [System.Collections.IEnumerable]$Data, | ||||||
|  |  | ||||||
|   $first = $true |         [string[]]$Columns = @('Namespace','Member Folder Target(s)','Replication Locations','Namespace Servers'), | ||||||
|   foreach ($r in $rows) { |  | ||||||
|     if (-not $first -and ([string]$r.$($Columns[0])) ) { |         # Reasonable max widths; tune to your console (these are content+padding widths) | ||||||
|       # Namespace changed → draw a heavy-ish separator |         [int[]]$MaxWidths = @(70, 70, 52, 30), | ||||||
|       Write-Host (DrawSep) |  | ||||||
|  |         [switch]$Ascii  # use +-| instead of box-drawing if your console garbles Unicode | ||||||
|  |       ) | ||||||
|  |  | ||||||
|  |       # Ensure arrays align | ||||||
|  |       if ($MaxWidths.Count -lt $Columns.Count) { | ||||||
|  |         $pad = New-Object System.Collections.Generic.List[int] | ||||||
|  |         $pad.AddRange($MaxWidths) | ||||||
|  |         for ($i=$MaxWidths.Count; $i -lt $Columns.Count; $i++) { $pad.Add(40) } | ||||||
|  |         $MaxWidths = $pad.ToArray() | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       # Characters | ||||||
|  |       if ($Ascii) { | ||||||
|  |         $H = @{ tl='+'; tr='+'; bl='+'; br='+'; hz='-'; vt='|'; tj='+'; mj='+'; bj='+' } | ||||||
|  |       } else { | ||||||
|  |         # Box-drawing | ||||||
|  |         $H = @{ tl='┌'; tr='┐'; bl='└'; br='┘'; hz='─'; vt='│'; tj='┬'; mj='┼'; bj='┴' } | ||||||
|  |         try { [Console]::OutputEncoding = [Text.UTF8Encoding]::UTF8 } catch {} | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       function TruncPad([string]$s, [int]$w) { | ||||||
|  |         if ($null -eq $s) { $s = '' } | ||||||
|  |         $s = $s -replace '\r','' -replace '\t',' ' | ||||||
|  |         if ($s.Length -le $w) { return $s.PadRight($w, ' ') } | ||||||
|  |         if ($w -le 1) { return $s.Substring(0, $w) } | ||||||
|  |         return ($s.Substring(0, $w-1) + '…') | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       # Materialize and compute widths (include one-space left/right padding for header and data) | ||||||
|  |       $rows = @($Data | ForEach-Object { | ||||||
|  |         $o = @{} | ||||||
|  |         foreach ($c in $Columns) { $o[$c] = [string]($_.$c) } | ||||||
|  |         [pscustomobject]$o | ||||||
|  |       }) | ||||||
|  |  | ||||||
|  |       $widths = @() | ||||||
|  |       for ($i=0; $i -lt $Columns.Count; $i++) { | ||||||
|  |         $col = $Columns[$i] | ||||||
|  |         # Start with header length including padding | ||||||
|  |         $max = (" " + $col + " ").Length | ||||||
|  |         foreach ($r in $rows) { | ||||||
|  |           $len = (" " + [string]$r.$col + " ").Length | ||||||
|  |           if ($len -gt $max) { $max = $len } | ||||||
|  |         } | ||||||
|  |         $widths += [Math]::Min($max, $MaxWidths[$i]) | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       # Line builders | ||||||
|  |       function DrawTop() { | ||||||
|  |           $line = $H.tl | ||||||
|  |           for ($i = 0; $i -lt $widths.Count; $i++) { | ||||||
|  |               $line += ($H.hz * $widths[$i]) | ||||||
|  |               if ($i -lt ($widths.Count - 1)) { | ||||||
|  |                   $line += $H.tj | ||||||
|  |               } else { | ||||||
|  |                   $line += $H.tr | ||||||
|  |               } | ||||||
|  |           } | ||||||
|  |           $line | ||||||
|  |       } | ||||||
|  |       function DrawMid([string[]]$Columns, [int[]]$widths, $H) { | ||||||
|  |         $line = $H.vt | ||||||
|  |         for ($i=0; $i -lt $widths.Count; $i++) { | ||||||
|  |           $line += TruncPad (" " + $Columns[$i] + " ") $widths[$i] | ||||||
|  |           $line += $H.vt | ||||||
|  |         } | ||||||
|  |         $line | ||||||
|  |       } | ||||||
|  |       function DrawSep() { | ||||||
|  |         $line = $H.vt | ||||||
|  |         for ($i=0; $i -lt $widths.Count; $i++) { | ||||||
|  |           $line += ($H.hz * $widths[$i]) | ||||||
|  |           $line += $H.vt | ||||||
|  |         } | ||||||
|  |         $line | ||||||
|  |       } | ||||||
|  |       function DrawHeaderSep() { | ||||||
|  |         $line = $H.vt | ||||||
|  |         for ($i=0; $i -lt $widths.Count; $i++) { | ||||||
|  |           $line += ($H.hz * $widths[$i]) | ||||||
|  |           $line += $H.vt | ||||||
|  |         } | ||||||
|  |         $line | ||||||
|  |       } | ||||||
|  |       function DrawBottom() { | ||||||
|  |           $line = $H.bl | ||||||
|  |           for ($i = 0; $i -lt $widths.Count; $i++) { | ||||||
|  |               $line += ($H.hz * $widths[$i]) | ||||||
|  |               if ($i -lt ($widths.Count - 1)) { | ||||||
|  |                   $line += $H.bj | ||||||
|  |               } else { | ||||||
|  |                   $line += $H.br | ||||||
|  |               } | ||||||
|  |           } | ||||||
|  |           $line | ||||||
|  |       } | ||||||
|  |       function DrawRow($r, [string[]]$Columns, [int[]]$widths, $H) { | ||||||
|  |         $line = $H.vt | ||||||
|  |         for ($i=0; $i -lt $widths.Count; $i++) { | ||||||
|  |           $val = [string]$r.($Columns[$i]) | ||||||
|  |           $line += TruncPad (" " + $val + " ") $widths[$i] | ||||||
|  |           $line += $H.vt | ||||||
|  |         } | ||||||
|  |         $line | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       # Render with group separators between namespaces (when the Namespace cell is non-empty) | ||||||
|  |       Write-Host (DrawTop) | ||||||
|  |       Write-Host (DrawMid -Columns $Columns -widths $widths -H $H) | ||||||
|  |       Write-Host (DrawHeaderSep) | ||||||
|  |  | ||||||
|  |       $first = $true | ||||||
|  |       foreach ($r in $rows) { | ||||||
|  |         if (-not $first -and ([string]$r.$($Columns[0])) ) { | ||||||
|  |           # Namespace changed → draw a separator | ||||||
|  |           Write-Host (DrawSep) | ||||||
|  |         } | ||||||
|  |         $first = $false | ||||||
|  |         Write-Host (DrawRow -r $r -Columns $Columns -widths $widths -H $H) | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       Write-Host (DrawBottom) | ||||||
|     } |     } | ||||||
|     $first = $false |  | ||||||
|     Write-Host (DrawRow $r) |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   Write-Host (DrawBottom) |     Write-DfsGrid -Data $rows | ||||||
| } |     ``` | ||||||
|  |  | ||||||
| Write-DfsGrid -Data $rows |  | ||||||
| ``` |  | ||||||
		Reference in New Issue
	
	Block a user