I'm creating a dynamic set for a domain controller parameter in one of my PS1 scripts. I am using [ValidateSet]
in the parameters but wanted to make this dynamic using Register-ArgumentCompleter
.
I've tried multiple ways in PS7 to use AutoCompleter to dynamically choose Domain Controllers that have the PDC role. I keep getting the default file options. I tried setting $null as per this article: Stack Flow. I couldn't get it to work.
Here is my code:
[CmdletBinding()]
param(
[System.Management.Automation.PSCredential]
$Credential,
[switch]$vcenterAccess = $false,
[string]$OutputPath = $ENV:HOMEPATH + '\Documents',
[string]$duzit = 'CF3' + (Get-Date -format 'yyMMdd'),
[switch]$listDCs,
[switch]$examples,
[string]$DomainController
)
$validPDCsb = {
param ($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParams)
$allPDCs = @()
$allPDCs = @(Get-AllDomainControllers -Role PDC).Name
$allPDCs | ? { $_ -like "*$wordToComplete*" } | % {
[System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
}
if (-not $allPDCs) {
$null
}
}
Register-ArgumentCompleter -ParameterName DomainController -ScriptBlock $validPDCsb
Function Get-CompanyServer {
if ($listDCs) { Get-DCList; exit }
if ($examples) { Get-Examples; exit }
Import-Module ImportExcel
$startTime = Get-Date
$startTime
$domainName = (Get-DomainName -DomainController $DomainController)
Write-Verbose ('DOMAIN: ' + $domainName)
if ($vcenterAccess -eq $true) { Connect-vCenter -Credential $Credential }
Get-ComputerList -DomainController $DomainController
$elapsedTime = $(get-date) - $startTime
$elapsedTime = $elapsedTime.Minutes
Write-Verbose ([string]$startTime + ' (Run time: ' + [string]$elapsedTime + ' Minutes)')
$serverCount = Get-ServerCount -DomainController $DomainController
Write-Verbose ('SERVER COUNT: ' + [string]$serverCount)
$FileOutput = ($OutputPath + '\' + $duzit + '-' + $domainName + '.xlsx')
Write-Host 'FILE SAVED: ' $FileOutput
Write-Verbose ('DUZIT (save this): ' + $duzit)
Get-Date
}
Function Get-ComputerList($DomainController) {
#Write-Verbose "Generating Computer List..."
$serverList = @()
[int]$counter = (Get-ADComputer -Filter { operatingSystem -like '*Windows server*' } -Server $DomainController -ResultSetSize 500 -Credential $Credential).Count
[int]$s = 0
Get-ADComputer -Filter { operatingSystem -like '*Windows server*' } -Server $DomainController -Properties * -ResultPageSize 500 -Credential $Credential | ? { ($_.OperatingSystem -like '*Windows server*') -or ($_.OperatingSystem -eq $null) } | select name, enabled, IPv4Address, operatingSystem, description, canonicalName | % {
$s++
$serverList += $_
Write-Progress -Activity ('Processing Computers [' + $s + '/' + $counter + '] : ' + $_.Name) -PercentComplete ($s / $counter * 100) -CurrentOperation $counter[$_]
}
#$serverList = @(Get-ADComputer -Filter {operatingSystem -like "*Windows server*"} -Server $DomainController -Properties * -ResultPageSize 500 -Credential $Credential | ? {($_.OperatingSystem -like "*Windows server*") -or ($_.OperatingSystem -eq $null)} | select name,enabled,IPv4Address,operatingSystem,description,canonicalName)
#[int]$count = $serverList.Count
$i = 0
$n = 0
Write-Verbose ("Systems found: '" + $counter + "'")
Write-Verbose 'PHASE ONE: Testing Connections...'
Write-Progress -Completed -Activity 'Completed'
foreach ($server in $serverList) {
$i++
$status = 'Down'
$p1sequence = [string]$i + '/' + [string]$counter
$elapsedTime = $(get-date) - $startTime
$elapsedTime = $elapsedTime.Minutes
Write-Verbose ($($server.name) + ': ' + $p1sequence)
if (Test-Connection $server.IPv4Address -Quiet) { $status = 'Up' }$server | Add-Member -MemberType NoteProperty -Name 'Status' -Value $status -Force
}
$elapsedTime = $(get-date) - $startTime
$elapsedTime = $elapsedTime.Minutes
Write-Verbose ('PHASE ONE: ' + $([string]$elapsedTime) + ' Minutes')
if ($vcenterAccess -eq $true) {
Write-Verbose 'PHASE TWO: Testing vCenter Connections...'
foreach ($server in $serverList) {
$n++
$p2sequence = [string]$n + '/' + [string]$counter
Write-Verbose ($($server.name) + ': ' + $p2sequence)
$vCenter = 'N/A'
$power = 'N/A'
$power = (Get-VM $server.Name).PowerState; $server | Add-Member -MemberType NoteProperty -Name 'PowerState' -Value $power -Force
$vCenter = (Get-VM $server.Name).Uid.Split(':')[0].Split('@')[1]; $server | Add-Member -MemberType NoteProperty -Name 'vCenter' -Value $vcenter -Force
}
$elapsedTime = $(get-date) - $startTime
$elapsedTime = $elapsedTime.Minutes
Write-Verbose ('PHASE TWO: ' + $([string]$elapsedTime) + ' Minutes')
}
$serverList = $serverList | sort name
#$serverList
$FileOutput = ($OutputPath + '\' + $duzit + '-' + $domainName + '.xlsx')
$serverList | Export-Excel -Path $FileOutput -WorksheetName $domainName -AutoSize -AutoFilter
}
Function Connect-vCenter {
Param(
[System.Management.Automation.PSCredential]$Credential
)
Write-Verbose 'Connecting vCenter Instances...'
Connect-VIServer corpvc01 -Credential $Credential -Force
Connect-VIServer ostpvc01 -Credential $Credential -Force
Connect-VIServer 10.200.52.2 -Credential $Credential -Force #AVS Azure East
Connect-VIServer 10.201.52.2 -Credential $Credential -Force #AVS Azure West
}
Function Get-ServerCount ($DomainController) {
$serverList = @(Get-ADComputer -Filter { operatingSystem -like '*Windows server*' } -Server $DomainController -Properties * -ResultPageSize 500 | ? { ($_.OperatingSystem -like '*Windows server*') -or ($_.OperatingSystem -eq $null) } | select name, enabled, IPv4Address, operatingSystem, description, canonicalName)
[int]$counter = $serverList.Count
$counter
}
Function Get-Examples {
$currentColor = ($Host.UI.RawUI.ForegroundColor)
$Host.UI.RawUI.ForegroundColor = 'Yellow'
Write-Host 'SET DOMAIN ADMIN CREDS'
Write-Host "`$Cred = Get-Credential"
Write-Host ''
Write-Host 'EXAMPLE COMMAND: CFEXTRANET'
Write-Host "Get-CompanyServer -Credential `$Cred -DomainController xdc1.cfextranet.com -Duzit `"CF3231114`" -OutputPath `"C:\Scripts\Lists\Excel`" -vCenterAccess:`$true -Verbose"
Write-Host ''
Write-Host 'EXAMPLE COMMAND: CFIORG Domain'
Write-Host "Get-CompanyServer -Credential `$Cred -DomainController DONCFIDVDC02 -Duzit `"CF3231114`" -OutputPath `"C:\Scripts\Lists\Excel`" -vCenterAccess:`$false -Verbose"
Write-Host "Get-CompanyServer -Credential `$Cred -DomainController CORCFILGDC01 -Duzit `"CF3231114`" -OutputPath `C:\Scripts\Lists\Excel`" -vCenterAccess:`$true -Verbose"
Write-Host "Get-CompanyServer -Credential `$Cred -DomainController CORCFIORGDC01 -Duzit `"CF3231114`" -OutputPath `"C:\Scripts\Lists\Excel`" -vCenterAccess:`$true -Verbose"
Write-Host "Get-CompanyServer -Credential `$Cred -DomainController MEDCFIMHDC01 -Duzit `"CF3231114`" -OutputPath `"C:\Scripts\Lists\Excel`" -vCenterAccess:`$false -Verbose"
Write-Host "Get-CompanyServer -Credential `$Cred -DomainController CORCFITRDC01 -Duzit `"CF3231114`" -OutputPath `"C:\Scripts\Lists\Excel`" -vCenterAccess:`$false -Verbose"
Write-Host ''
Write-Host 'EXAMPLE COMMAND: GROWHOW'
Write-Host "Get-CompanyServer -Credential `$Cred -DomainController incghsdc1.growhow.local -Duzit `"CF3231114`" -OutputPath `"C:\Scripts\Lists\Excel`" -vCenterAccess:`$false -Verbose"
Write-Host ''
$Host.UI.RawUI.ForegroundColor = 'Green'
Write-Host '-DUZIT: This alphanumeric value is a combination of CF3 (3 denoting Report) and date string 11/14/23 (231114).'
Write-Host '-DUZIT: This must be kept when generating multiple reports for the one master report (REF: Merge-CompanyServer.ps1)'
Write-Host '-DUZIT: This value is gernerated automatically but you can force a value depending on your report groupings'
Write-Host '-OUTPUT PATH: Make this a consistent diretory to group all your reportrs for the master report (REF: Merge-CompanyServer.ps1)'
Write-Host '-DOMAIN CONTROLLER: (Get-CompanyServer -listDCs). Use a specific DC for each of the domains you are generating the single report'
Write-Host '-CREDENTIAL: These are your Domain Admin creds that are needed to log into vCenter and DCs'
Write-Host '-VCENTER ACCESS: CFILG, CFEXTRANET and CFIORG are the only domains where we have vCenter access. Set the value to true for those reports'
Write-Host '-VERBOSE: ALWAYS use the verbose swtich to see the activity on the report creation.'
$Host.UI.RawUI.ForegroundColor = $currentColor
}
Function Get-DomainName ($DomainController) {
if ($DomainController -like '*FILG*') { $domainName = 'CFILG' }
if ($DomainController -like '*FIMH*') { $domainName = 'CFIMH' }
if ($DomainController -like '*FITR*') { $domainName = 'CFITR' }
if ($DomainController -like '*FIORG*') { $domainName = 'CFIORG' }
if ($DomainController -like '*FIDV*') { $domainName = 'CFIDV' }
if ($DomainController -like 'xdc*') { $domainName = 'CFEXTRANET' }
if ($DomainController -like '*GHSDC*') { $domainName = 'GROWHOW' }
$domainName
}
Function Get-DCList {
$dclist = (Get-ADForest).Domains | % { Get-ADDomainController -Filter * -Server $_ } | ft -Property Name, Domain, IPv4Address, OperatingSystem, OperationMasterRoles -AutoSize
$cfextranet = (Get-ADForest -Server xdc1.cfextranet.com).Domains | % { Get-ADDomainController -Filter * -Server $_ } | ft -Property Name, Domain, IPv4Address, OperatingSystem, OperationMasterRoles -AutoSize
$growhow = (Get-ADForest -Server INCGHSDC1.GROWHOW.LOCAL).Domains | % { Get-ADDomainController -Filter * -Server $_ } | ft -Property Name, Domain, IPv4Address, OperatingSystem, OperationMasterRoles -AutoSize
$cfextranet
$dclist
$growhow
}
Function Get-AllDomainControllers {
$domains = (Get-ADForest).domains
$dcs = foreach ($domain in $domains) { Get-ADDomainController -Discover -DomainName $domain }
switch ($Role) {
'None' {
$result = foreach ($dc in $dcs) {
$ForestMode = (Get-ADForest -Credential $Credential).ForestMode
$DomainMode = (Get-ADDomain -Server $dc -Credential $Credential).DomainMode
Get-ADDomainController -Filter * -Server $dc -Credential $Credential | select Name, HostName, IPv4Address, Domain, OperatingSystem, @{Name = 'DomainMode'; Expression = { $DomainMode } }, @{Name = 'ForestMode'; Expression = { $ForestMode } }, IsGlobalCatalog, OperationMasterRoles, Site, ServerObjectGuid
}
}
'PDC' {
$result = foreach ($dc in $dcs) {
$DomainMode = (Get-ADDomain -Server $dc -Credential $Credential).DomainMode
Get-ADDomainController -Filter * -Server $dc -Credential $Credential | ? { $_.OperationMasterRoles -match 'PDCEmulator' } | select Name, HostName, IPv4Address, Domain, OperatingSystem, @{Name = 'DomainMode'; Expression = { $DomainMode } }, IsGlobalCatalog, OperationMasterRoles, Site, ServerObjectGuid
}
}
'RID' {
$result = foreach ($dc in $dcs) {
$DomainMode = (Get-ADDomain -Server $dc -Credential $Credential).DomainMode
Get-ADDomainController -Filter * -Server $dc -Credential $Credential | ? { $_.OperationMasterRoles -match 'RIDMaster' } | select HostName, IPv4Address, Domain, OperatingSystem, @{Name = 'DomainMode'; Expression = { $DomainMode } }, IsGlobalCatalog, OperationMasterRoles, Site, ServerObjectGuid
}
}
'Infrastructure' {
$result = foreach ($dc in $dcs) {
$DomainMode = (Get-ADDomain -Server $dc -Credential $Credential).DomainMode
Get-ADDomainController -Filter * -Server $dc -Credential $Credential | ? { $_.OperationMasterRoles -match 'InfrastructureMaster' } | select Name, HostName, IPv4Address, Domain, OperatingSystem, @{Name = 'DomainMode'; Expression = { $DomainMode } }, IsGlobalCatalog, OperationMasterRoles, Site, ServerObjectGuid
}
}
'Naming' {
$ForestMode = (Get-ADForest -Credential $Credential).ForestMode
$result = foreach ($dc in $dcs) { Get-ADDomainController -Filter * -Server $dc -Credential $Credential | ? { $_.OperationMasterRoles -match 'DomainNamingMaster' } | select Name, HostName, IPv4Address, Domain, OperatingSystem, @{Name = 'ForestMode'; Expression = { $ForestMode } }, IsGlobalCatalog, OperationMasterRoles, Site, ServerObjectGuid }
}
'Schema' {
$SchemaServer = (Get-ADForest -Credential $Credential).SchemaMaster
$ForestMode = (Get-ADForest -Credential $Credential).ForestMode
$SchemaVersion = Get-ADObject (Get-ADRootDSE).schemaNamingContext -Property objectVersion -Server $SchemaServer -Credential $Credential
$result = foreach ($dc in $dcs) { Get-ADDomainController -Filter * -Server $dc -Credential $Credential | ? { $_.OperationMasterRoles -match 'SchemaMaster' } | select Name, HostName, IPv4Address, Domain, OperatingSystem, @{Name = 'SchemaVersion'; Expression = { $SchemaVersion.objectVersion } }, @{Name = 'ForestMode'; Expression = { $ForestMode } }, IsGlobalCatalog, OperationMasterRoles, Site, ServerObjectGuid }
}
}
$result
}
Get-CompanyServer
If you place your Register-ArgumentCompleter
call inside your script, it won't be executed until after the first successful invocation of your script.
-DomainController
arguments will initially not tab-complete.To get tab-completion from the beginning, use an [ArgumentCompleter()]
attribute instead, and decorate your [string]$DomainController
parameter declaration with it.
Here's a minimal example:
param(
[ArgumentCompleter({
param($commandName, $parameterName, $wordToComplete) # , $commandAst, $preBoundParameters omitted
# Hard-coded sample list of PDCs
# Place the real code to find the PDCs *directly in here*.
# You can NOT call functions defined later in the script here.
[array] $allPDCs = 'foo', 'bar', 'baz'
# Return the ones that prefix-match what was typed so far, if anything.
$allPDCs -like "$wordToComplete*"
})]
[string] $DomainController
)
$DomainController # diagnostic output of the argument
A -DomainController
argument then tab-completes to foo
, bar
or baz
, also on first invocation.