ADWinHostFirewallExport.psm1
#Region '.\prefix.ps1' -1 # Ensure C# class is loaded before module functions if (-not ("ResourceStringResolver" -as [type])) { $csFilePath = Join-Path $PSScriptRoot "Types\ResourceStringResolver.cs" if (Test-Path $csFilePath) { Write-Verbose "Compiling and loading C# class from: $csFilePath" Add-Type -Path $csFilePath -ErrorAction Stop } else { Write-Warning "C# file not found: $csFilePath. Resource string resolution may not work." } } #EndRegion '.\prefix.ps1' 13 #Region '.\Classes\FirewallRule.ps1' -1 class FirewallRule { [string]$ComputerName [string]$Group [string]$DisplayName [string]$FWProfile [bool]$IsDomain [bool]$IsPrivate [bool]$IsPublic [bool]$IsAny [string]$Action [bool]$Enabled [string]$Direction [string]$Protocol [string]$LocalPort [string]$LocalAddress [string]$RemoteAddress [string]$Program FirewallRule([string]$computerName, [string]$group, [string]$displayName, [string]$FWProfile, [bool]$isDomain, [bool]$isPrivate, [bool]$isPublic, [bool]$isAny, [string]$action, [bool]$enabled, [string]$direction, [string]$protocol, [string]$localPort, [string]$localAddress, [string]$remoteAddress, [string]$program) { $this.ComputerName = $computerName $this.Group = $group $this.DisplayName = $displayName $this.FWProfile = $FWProfile $this.IsDomain = $isDomain $this.IsPrivate = $isPrivate $this.IsPublic = $isPublic $this.IsAny = $isAny $this.Action = $action $this.Enabled = $enabled $this.Direction = $direction $this.Protocol = $protocol $this.LocalPort = $localPort $this.LocalAddress = $localAddress $this.RemoteAddress = $remoteAddress $this.Program = $program } } #EndRegion '.\Classes\FirewallRule.ps1' 42 #Region '.\Private\Get-ADHostFirewallStatus.ps1' -1 <# .SYNOPSIS Retrieves the firewall status of a local or remote machine. .DESCRIPTION This function retrieves the firewall status for either a local or remote machine. It gathers firewall profile details including domain, private, and public profiles. .PARAMETER ComputerName The name(s) of the remote computer(s) to retrieve firewall status from. .PARAMETER Local Use this switch to retrieve firewall status from the local machine. .EXAMPLE Get-ADHostFirewallStatus -ComputerName "Server01" Retrieves firewall status from the remote machine "Server01". .EXAMPLE Get-ADHostFirewallStatus -Local Retrieves firewall status from the local machine. .OUTPUTS PSCustomObject. Each object contains firewall profile settings. .NOTES Requires administrative privileges to execute. #> function Get-ADHostFirewallStatus { [CmdletBinding( SupportsShouldProcess = $true, DefaultParameterSetName = 'Remote', ConfirmImpact = 'Low' )] [OutputType([PSCustomObject])] param ( [Parameter( Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'Remote' )] [string[]]$ComputerName, [Parameter( Mandatory = $true, ParameterSetName = 'Local' )] [switch]$Local ) begin { Write-TimestampedMessage 'Initializing Get-ADHostFirewallStatus function.' Write-Progress -Activity 'Initializing' -Status 'Preparing to query firewall status...' -PercentComplete 0 $results = New-Object System.Collections.Generic.List[Object] $totalComputers = $ComputerName.Count $count = 0 } process { try { if ($PSCmdlet.ShouldProcess('Firewall Status', 'Retrieve firewall information')) { switch ($PSCmdlet.ParameterSetName) { 'Remote' { Write-TimestampedMessage "Retrieving firewall status for remote machines: $($ComputerName -join ', ')" foreach ($server in $ComputerName) { $count++ $percentComplete = [math]::Round(($count / $totalComputers) * 100) Write-Progress -Activity 'Retrieving Firewall Status' -Status "Processing $server ($count of $totalComputers)" -PercentComplete $percentComplete Write-TimestampedMessage "Processing machine: $server" try { $result = Invoke-Command -ComputerName $server -ScriptBlock { $profiles = Get-NetFirewallProfile | Group-Object -Property Name -AsHashTable -AsString [PSCustomObject]@{ ComputerName = $env:COMPUTERNAME Domain_Enabled = $profiles.Domain.Enabled Domain_LogFileName = $profiles.Domain.LogFileName Domain_LogMaxSizeKilobytes = $profiles.Domain.LogMaxSizeKilobytes Domain_LogAllowed = $profiles.Domain.LogAllowed Domain_LogBlocked = $profiles.Domain.LogBlocked # Private Private_Enabled = $profiles.Private.Enabled Private_LogFileName = $profiles.Private.LogFileName Private_LogMaxSizeKilobytes = $profiles.Private.LogMaxSizeKilobytes Private_LogAllowed = $profiles.Private.LogAllowed Private_LogBlocked = $profiles.Private.LogBlocked # Public Public_Enabled = $profiles.Public.Enabled Public_LogFileName = $profiles.Public.LogFileName Public_LogMaxSizeKilobytes = $profiles.Public.LogMaxSizeKilobytes Public_LogAllowed = $profiles.Public.LogAllowed Public_LogBlocked = $profiles.Public.LogBlocked } } -ErrorAction Stop $cleanResult = $result | Select-Object -Property * -ExcludeProperty PSComputerName, RunspaceId $results.Add($cleanResult) | Out-Null } catch { throw "Error retrieving firewall status from $server`: $($_.Exception.Message)" } } } 'Local' { Write-TimestampedMessage 'Retrieving firewall status for the local machine.' try { Write-Progress -Activity 'Retrieving Firewall Status' -Status 'Processing Local Machine' -PercentComplete 100 $profiles = Get-NetFirewallProfile | Group-Object -Property Name -AsHashTable -AsString $localResult = [PSCustomObject]@{ ComputerName = $env:COMPUTERNAME Domain_Enabled = $profiles.Domain.Enabled Domain_LogFileName = $profiles.Domain.LogFileName Domain_LogMaxSizeKilobytes = $profiles.Domain.LogMaxSizeKilobytes Domain_LogAllowed = $profiles.Domain.LogAllowed Domain_LogBlocked = $profiles.Domain.LogBlocked # Private Private_Enabled = $profiles.Private.Enabled Private_LogFileName = $profiles.Private.LogFileName Private_LogMaxSizeKilobytes = $profiles.Private.LogMaxSizeKilobytes Private_LogAllowed = $profiles.Private.LogAllowed Private_LogBlocked = $profiles.Private.LogBlocked # Public Public_Enabled = $profiles.Public.Enabled Public_LogFileName = $profiles.Public.LogFileName Public_LogMaxSizeKilobytes = $profiles.Public.LogMaxSizeKilobytes Public_LogAllowed = $profiles.Public.LogAllowed Public_LogBlocked = $profiles.Public.LogBlocked } $results.Add($localResult) | Out-Null } catch { throw "Error retrieving local firewall status: $($_.Exception.Message)" } } } } else { throw 'Operation canceled by ShouldProcess check.' } } catch { throw "Unexpected error: $($_.Exception.Message)" } } end { Write-Progress -Activity 'Retrieving Firewall Status' -Status 'Completed processing all hosts.' -Completed return $results } } #EndRegion '.\Private\Get-ADHostFirewallStatus.ps1' 138 #Region '.\Private\Resolve-FirewallResourceString.ps1' -1 <# .SYNOPSIS Resolves a firewall resource string to its actual value. .DESCRIPTION This function takes a firewall resource string (e.g., "@C:\Windows\System32\firewallapi.dll,-28546") and resolves it to a human-readable string using the ResourceStringResolver class. .PARAMETER ResourceString The resource string to resolve. Can be null or empty. .EXAMPLE Resolve-FirewallResourceString -ResourceString "@C:\Windows\System32\firewallapi.dll,-28546" Returns the resolved string. .OUTPUTS [string] - The resolved firewall resource string. .NOTES This function relies on the ResourceStringResolver C# class. #> function Resolve-FirewallResourceString { [CmdletBinding()] [OutputType([string])] param( [Parameter()] [AllowEmptyString()] [AllowNull()] [string]$ResourceString ) try { # If input is null or empty, return it as-is if ([string]::IsNullOrWhiteSpace($ResourceString)) { Write-TimestampedMessage "Resource string is null or empty. Returning as-is." return $ResourceString } Write-TimestampedMessage "Resolving firewall resource string: $ResourceString" # Call the C# method to resolve $resolvedString = [ResourceStringResolver]::GetString($ResourceString) Write-TimestampedMessage "Resolved string: $resolvedString" return $resolvedString } catch { Write-Warning "Failed to resolve resource string: $ResourceString. Returning input value." return $ResourceString } } #EndRegion '.\Private\Resolve-FirewallResourceString.ps1' 43 #Region '.\Private\Write-TimeStampedMessage.ps1' -1 function Write-TimestampedMessage { param( [Parameter(Mandatory)] [string]$Message, [Parameter()] [ValidateSet("Verbose", "Warning", "Error", "Info", "Debug")] [string]$Type = "Verbose" ) $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss.ffff" switch ($Type) { "Verbose" { Write-Verbose "[$timestamp] $Message" } "Warning" { Write-Warning "[$timestamp] $Message" } "Error" { Write-Error "[$timestamp] $Message" } "Info" { Write-Information "[$timestamp] $Message" } "Debug" { Write-Debug "[$timestamp] $Message" } default { Write-Host "[$timestamp] $Message" } } } #EndRegion '.\Private\Write-TimeStampedMessage.ps1' 19 #Region '.\Public\Get-ADHostFirewallRulesExport.ps1' -1 <# .SYNOPSIS Retrieves firewall rules from remote machines with filtering options. .DESCRIPTION This function collects firewall rules from the specified remote computers. It allows filtering based on rule status (Enabled, Disabled, or All) and direction (Inbound, Outbound, or All). Additionally, it resolves rule group names, includes protocol and port information, and retrieves associated program paths, local addresses, and remote addresses. .PARAMETER ComputerName Specifies one or more remote computers from which to retrieve firewall rules. .PARAMETER RuleStatus Specifies which firewall rules to retrieve based on their enabled status. Options: - "All" : Retrieves all firewall rules (enabled and disabled). - "Enabled" : Retrieves only enabled firewall rules (Default). - "Disabled" : Retrieves only disabled firewall rules. .PARAMETER Direction Specifies the direction of firewall rules to retrieve. Options: - "All" : Retrieves both inbound and outbound rules. - "Inbound" : Retrieves only inbound firewall rules (Default). - "Outbound" : Retrieves only outbound firewall rules. .EXAMPLE Get-ADHostFirewallRulesExport -ComputerName "Server01" Retrieves only enabled inbound firewall rules from "Server01" (default behavior). .EXAMPLE Get-ADHostFirewallRulesExport -ComputerName "Server01" -RuleStatus All -Direction Outbound Retrieves all outbound firewall rules from "Server01". .EXAMPLE Get-ADHostFirewallRulesExport -ComputerName "Server01", "Server02" -RuleStatus Disabled Retrieves only disabled inbound firewall rules from both "Server01" and "Server02". .EXAMPLE "Server01", "Server02" | Get-ADHostFirewallRulesExport -Direction All Retrieves both inbound and outbound enabled firewall rules from "Server01" and "Server02". .OUTPUTS [FirewallRule] (Custom Class). Each object contains details about a firewall rule, including: - ComputerName : The remote host where the firewall rule is applied. - Group : The resolved name of the firewall rule group. - DisplayName : The display name of the firewall rule. - FWProfile : The firewall profile(s) associated with the rule. - IsDomain : Indicates whether the rule applies to the domain profile. - IsPrivate : Indicates whether the rule applies to the private profile. - IsPublic : Indicates whether the rule applies to the public profile. - IsAny : Indicates if the rule applies to all profiles. - Action : Whether the rule allows or blocks traffic. - Enabled : Indicates whether the rule is enabled. - Direction : Whether the rule applies to inbound or outbound traffic. - Protocol : The protocol associated with the firewall rule. - LocalPort : The local port(s) affected by the rule. - LocalAddress : The local IP addresses affected by the rule. - RemoteAddress : The remote IP addresses affected by the rule. - Program : The executable associated with the firewall rule (if applicable). .NOTES - Requires administrative privileges on remote machines. - Uses Invoke-Command to query firewall rules remotely. - Resolves localized firewall rule group names where applicable. - Optimized to retrieve address filters and application filters in batch. - Uses lookup tables to efficiently map rule instance IDs to addresses and programs. .COMPONENT Windows Defender Firewall with Advanced Security (NetSecurity module) .LINK https://docs.microsoft.com/en-us/powershell/module/netsecurity/get-netfirewallrule .LINK https://docs.microsoft.com/en-us/powershell/module/netsecurity/get-netfirewalladdressfilter .LINK https://docs.microsoft.com/en-us/powershell/module/netsecurity/get-netfirewallapplicationfilter #> function Get-ADHostFirewallRulesExport { [CmdletBinding( SupportsShouldProcess = $true, ConfirmImpact = 'Low' )] [OutputType([FirewallRule])] param( [Parameter(Mandatory, ValueFromPipelineByPropertyName = $true)] [string[]]$ComputerName, [Parameter()] [ValidateSet('All', 'Enabled', 'Disabled')] [string]$RuleStatus = 'Enabled', [Parameter()] [ValidateSet('All', 'Inbound', 'Outbound')] [string]$Direction = 'Inbound' ) begin { Write-TimestampedMessage 'Initializing Get-ADHostFirewallRulesExport function.' $results = [System.Collections.Generic.List[FirewallRule]]::new() # Load C# class for resolving resource strings #$resolverDefinition = Get-Content -Path (Join-Path $PSScriptRoot 'Types\ResourceStringResolver.cs') -Raw $resolverDefinition = [ResourceStringResolver]::SourceCode } process { $total = $ComputerName.Count $count = 0 foreach ($server in $ComputerName) { $count++ Write-Progress -Activity 'Retrieving Firewall Rules' ` -Status "Processing: $server ($count of $total)" ` -PercentComplete (($count / $total) * 100) if ($PSCmdlet.ShouldProcess($server, 'Retrieve firewall rules')) { Write-TimestampedMessage "Processing firewall rules for: $server" try { # Invoke command with the resolver type definition $remoteData = Invoke-Command -ComputerName $server -ScriptBlock { param($RuleStatus, $Direction, $resolverDefinition) # Ensure NetSecurity is imported Import-Module NetSecurity -ErrorAction Continue # Load ResourceStringResolver if not already defined if (-not ("ResourceStringResolver" -as [type])) { Add-Type -TypeDefinition $resolverDefinition -Language CSharp } # Convert RuleStatus into string values for filtering $enabledValue = switch ($RuleStatus) { 'Enabled' { $true } 'Disabled' { $false } default { $null } # "All" } # Retrieve all firewall rules once $firewallRules = Get-NetFirewallRule if ($null -ne $enabledValue) { $firewallRules = $firewallRules | Where-Object { $_.Enabled -eq $enabledValue } } if ($Direction -ne 'All') { $firewallRules = $firewallRules | Where-Object { $_.Direction -eq $Direction } } # Retrieve all address filters once $addressFilters = Get-NetFirewallAddressFilter -All # Retrieve all application filters once $applicationFilters = Get-NetFirewallApplicationFilter -All # Create lookup tables $addressLookup = @{} foreach ($filter in $addressFilters) { $addressLookup[$filter.InstanceID] = @{ LocalAddress = $filter.LocalAddress RemoteAddress = $filter.RemoteAddress } } $appLookup = @{} foreach ($appFilter in $applicationFilters) { $appLookup[$appFilter.InstanceID] = $appFilter.Program } $resolvedRules = @() foreach ($rule in $firewallRules) { # For port/protocol info $portFilter = $rule | Get-NetFirewallPortFilter -ErrorAction SilentlyContinue # Resolve firewall rule group name remotely $resolvedGroup = [ResourceStringResolver]::GetString($rule.Group) # Convert FWProfile array to a comma-separated string $profileList = $rule.Profile -join ', ' # Handle profile conditions correctly $isDomain = $rule.Profile -contains 'Domain' $isPrivate = $rule.Profile -contains 'Private' $isPublic = $rule.Profile -contains 'Public' # If 'Any' is in the profile list, assume all profiles apply if ($rule.Profile -contains 'Any') { $isDomain = $true $isPrivate = $true $isPublic = $true } $isAny = $isDomain -and $isPrivate -and $isPublic # Get the associated addresses $localAddress = 'Any' $remoteAddress = 'Any' if ($addressLookup.ContainsKey($rule.InstanceID)) { $localAddress = $addressLookup[$rule.InstanceID].LocalAddress $remoteAddress = $addressLookup[$rule.InstanceID].RemoteAddress } # Get the associated program $program = 'N/A' if ($appLookup.ContainsKey($rule.InstanceID)) { $program = $appLookup[$rule.InstanceID] } # Build the resolved rule object $resolvedRules += [PSCustomObject]@{ Group = $resolvedGroup DisplayName = $rule.DisplayName FWProfile = $profileList IsDomain = $isDomain IsPrivate = $isPrivate IsPublic = $isPublic IsAny = $isAny Action = $rule.Action Enabled = $rule.Enabled Direction = $rule.Direction Protocol = $portFilter.Protocol LocalPort = $portFilter.LocalPort LocalAddress = $localAddress RemoteAddress = $remoteAddress Program = $program } } return $resolvedRules } -ArgumentList $RuleStatus, $Direction, $resolverDefinition -ErrorAction Stop # Convert the PSCustomObjects from remote to FirewallRule objects locally foreach ($ruleObj in $remoteData) { $firewallRule = [FirewallRule]::new( $server, $ruleObj.Group, $ruleObj.DisplayName, $ruleObj.FWProfile, $ruleObj.IsDomain, $ruleObj.IsPrivate, $ruleObj.IsPublic, $ruleObj.IsAny, $ruleObj.Action, [System.Convert]::ToBoolean($ruleObj.Enabled), $ruleObj.Direction, $ruleObj.Protocol, $ruleObj.LocalPort, $ruleObj.LocalAddress, $ruleObj.RemoteAddress, $ruleObj.Program ) [void]$results.Add($firewallRule) } } catch { Write-Warning "Error retrieving firewall rules from $server`: $($_.Exception.Message)" } } else { Write-TimestampedMessage "Operation canceled for $server" } } Write-Progress -Activity 'Retrieving Firewall Rules' -Completed } end { Write-TimestampedMessage 'Returning results for Get-ADHostFirewallRulesExport function.' return $results } } #EndRegion '.\Public\Get-ADHostFirewallRulesExport.ps1' 235 #Region '.\Public\Get-ADHostFirewallStatusReport.ps1' -1 <# .SYNOPSIS Retrieves firewall status and manageability information for specified hosts. .DESCRIPTION This function retrieves firewall status and evaluates remote manageability for a list of specified computers. It determines if each host is remotely accessible via WS-Management (WinRM) and retrieves firewall configuration settings for accessible hosts. If a host is unreachable, "N/A" values are assigned to firewall properties. .PARAMETER ComputerName Specifies one or more computer names from which to retrieve firewall status and manageability information. The function expects an array of computer names. .EXAMPLE Get-ADHostFirewallStatusReport -ComputerName "Server01" Retrieves firewall status and manageability details for "Server01". .EXAMPLE $activeServers = Get-ADHostManageability -DaysInactive 30 -Servers Get-ADHostFirewallStatusReport -ComputerName $activeServers.ComputerName Retrieves firewall status for all Active Directory servers that were active within the last 30 days. .EXAMPLE Get-ADHostFirewallStatusReport -ComputerName @("Workstation01", "Workstation02") Retrieves firewall status and manageability details for the specified workstations. .OUTPUTS PSCustomObject. Each object contains: - ComputerName : The name of the remote host. - IPAddress : The detected network address (if available). - IsRemotable : Indicates if the host is reachable via WS-Management. - Domain_Enabled : Firewall status for the Domain profile. - Domain_LogFileName : The log file path for the Domain profile. - Domain_LogMaxSizeKilobytes : The maximum log file size for the Domain profile. - Domain_LogAllowed : Indicates if allowed traffic is logged in the Domain profile. - Domain_LogBlocked : Indicates if blocked traffic is logged in the Domain profile. - Private_Enabled : Firewall status for the Private profile. - Private_LogFileName : The log file path for the Private profile. - Private_LogMaxSizeKilobytes: The maximum log file size for the Private profile. - Private_LogAllowed : Indicates if allowed traffic is logged in the Private profile. - Private_LogBlocked : Indicates if blocked traffic is logged in the Private profile. - Public_Enabled : Firewall status for the Public profile. - Public_LogFileName : The log file path for the Public profile. - Public_LogMaxSizeKilobytes : The maximum log file size for the Public profile. - Public_LogAllowed : Indicates if allowed traffic is logged in the Public profile. - Public_LogBlocked : Indicates if blocked traffic is logged in the Public profile. .NOTES - This function requires administrative privileges to execute. - Hosts must have WS-Management (WinRM) enabled to retrieve firewall settings remotely. - If a host is unreachable, firewall properties are set to "N/A". - The function updates progress dynamically as hosts are processed. .TROUBLESHOOTING NOTE - Ensure that the firewall allows remote management. - If a host is reported as unreachable, confirm network connectivity and the WS-Management service status. - If WinRM is disabled, enable it using: `Enable-PSRemoting -Force` .COMPONENT Windows Defender Firewall with Advanced Security (NetSecurity module) .LINK https://docs.microsoft.com/en-us/powershell/module/netsecurity/get-netfirewallprofile .LINK https://docs.microsoft.com/en-us/powershell/module/netsecurity/get-netfirewallrule #> function Get-ADHostFirewallStatusReport { [CmdletBinding( SupportsShouldProcess = $true, ConfirmImpact = 'Low' )] [OutputType([PSCustomObject])] param( [Parameter(Mandatory, ValueFromPipelineByPropertyName = $true)] [string[]]$ComputerName ) begin { Write-TimestampedMessage 'Initializing Get-ADHostFirewallStatusReport function.' Write-Progress -Activity "Initializing" -Status "Preparing to retrieve firewall information..." -PercentComplete 0 } process { if ($PSCmdlet.ShouldProcess("Hosts", "Retrieve manageability and firewall status")) { try { $totalHosts = $ComputerName.Count $count = 0 $results = foreach ($host in $ComputerName) { $count++ $percentComplete = [math]::Round(($count / $totalHosts) * 100) Write-TimestampedMessage "Processing: $host" # Test manageability using Test-WSMan $testRemoting = Test-WSMan -ComputerName $host -ErrorAction SilentlyContinue $isRemotable = $null -ne $testRemoting if ($isRemotable) { try { # ✅ **Update progress BEFORE firewall query** Write-Progress -Activity "Retrieving Firewall Status" -Status "Querying $host firewall settings..." -PercentComplete $percentComplete Write-TimestampedMessage "Host $host is remotely accessible. Retrieving firewall status..." $fwResult = Get-ADHostFirewallStatus -ComputerName $host $fw = $fwResult[0] # Expecting a single object [PSCustomObject]@{ ComputerName = $host IPAddress = $testRemoting.NetworkAddress IsRemotable = $isRemotable Domain_Enabled = $fw.Domain_Enabled Domain_LogFileName = $fw.Domain_LogFileName Domain_LogMaxSizeKilobytes = $fw.Domain_LogMaxSizeKilobytes Domain_LogAllowed = $fw.Domain_LogAllowed Domain_LogBlocked = $fw.Domain_LogBlocked # Private Private_Enabled = $fw.Private_Enabled Private_LogFileName = $fw.Private_LogFileName Private_LogMaxSizeKilobytes = $fw.Private_LogMaxSizeKilobytes Private_LogAllowed = $fw.Private_LogAllowed Private_LogBlocked = $fw.Private_LogBlocked # Public Public_Enabled = $fw.Public_Enabled Public_LogFileName = $fw.Public_LogFileName Public_LogMaxSizeKilobytes = $fw.Public_LogMaxSizeKilobytes Public_LogAllowed = $fw.Public_LogAllowed Public_LogBlocked = $fw.Public_LogBlocked } } catch { throw "Error retrieving firewall status for $host`: $($_.Exception.Message)" } } else { Write-TimestampedMessage "Host $host is NOT remotely accessible. Assigning 'N/A' values." [PSCustomObject]@{ ComputerName = $host IPAddress = 'N/A' IsRemotable = $isRemotable Domain_Enabled = 'N/A' Domain_LogFileName = 'N/A' Domain_LogMaxSizeKilobytes = 'N/A' Domain_LogAllowed = 'N/A' Domain_LogBlocked = 'N/A' # Private Private_Enabled = 'N/A' Private_LogFileName = 'N/A' Private_LogMaxSizeKilobytes = 'N/A' Private_LogAllowed = 'N/A' Private_LogBlocked = 'N/A' # Public Public_Enabled = 'N/A' Public_LogFileName = 'N/A' Public_LogMaxSizeKilobytes = 'N/A' Public_LogAllowed = 'N/A' Public_LogBlocked = 'N/A' } } } Write-Progress -Activity "Processing Hosts" -Status "Completed processing hosts." -Completed } catch { Write-Progress -Activity "Processing Hosts" -Status "Error encountered. See logs." -Completed throw "Error retrieving host manageability and firewall status: $($_.Exception.Message)" } } else { Write-TimestampedMessage "Operation canceled by ShouldProcess." } } end { Write-Progress -Activity "Finalizing" -Status "Returning results..." -PercentComplete 100 -Completed Write-TimestampedMessage "End of Get-ADHostFirewallStatusReport function." return $results } } #EndRegion '.\Public\Get-ADHostFirewallStatusReport.ps1' 166 #Region '.\Public\Get-ADHostManageability.ps1' -1 <# .SYNOPSIS Retrieves Active Directory computers and determines their manageability. .DESCRIPTION Queries Active Directory for computers based on the specified criteria. Checks whether each computer is remotely manageable via WS-Man. .PARAMETER DaysInactive The number of days since the last logon timestamp to consider a computer active. .PARAMETER Servers If specified, filters results to include only servers. .PARAMETER Workstations If specified, filters results to include only workstations. .PARAMETER OperatingSystemSearchString A custom operating system search string to filter results. .PARAMETER SearchBase The LDAP search base to limit the query scope. .EXAMPLE Get-ADHostManageability -DaysInactive 60 -Servers Retrieves all servers active within the last 60 days. .EXAMPLE Get-ADHostManageability -Workstations -OperatingSystemSearchString "Windows 10" Retrieves all Windows 10 workstations that are considered active. .OUTPUTS PSCustomObject. Each object contains host details and manageability status. .NOTES Requires Active Directory module and administrative privileges. #> function Get-ADHostManageability { [CmdletBinding( SupportsShouldProcess = $true, ConfirmImpact = 'Low' )] [OutputType([PSCustomObject])] param( [Parameter()] [int]$DaysInactive = 90, [Parameter()] [switch]$Servers, [Parameter()] [switch]$Workstations, [Parameter()] [string]$OperatingSystemSearchString, [Parameter()] [string]$SearchBase ) begin { Write-TimestampedMessage 'Initializing Get-ADHostManageability function.' Write-Progress -Activity 'Initializing' -Status 'Setting up search filters...' -PercentComplete 0 $cutoffDate = (Get-Date).AddDays(-$DaysInactive) Write-TimestampedMessage "Searching for Active Directory computers active since $cutoffDate" # Determine search pattern for OS filtering if ($Servers) { $searchPattern = '*server*' } elseif ($Workstations) { $searchPattern = '*windows 1*' } elseif ($OperatingSystemSearchString) { $searchPattern = "*$OperatingSystemSearchString*" } else { $searchPattern = '*' } Write-TimestampedMessage "Operating system search pattern: $searchPattern" } process { if ($PSCmdlet.ShouldProcess('Active Directory Computers', 'Retrieve AD computer objects')) { try { Write-Progress -Activity 'Querying Active Directory' -Status 'Retrieving computer objects...' -PercentComplete 10 if ($SearchBase) { Write-TimestampedMessage "Using SearchBase: $SearchBase" $allComputers = Get-ADComputer -SearchBase $SearchBase ` -Filter { LastLogonTimeStamp -gt $cutoffDate } ` -Properties ipv4Address, OperatingSystem, LastLogonTimeStamp ` -ErrorAction Stop } else { Write-TimestampedMessage "Querying all AD computers with OS filter: $searchPattern" $allComputers = Get-ADComputer -Filter { (LastLogonTimeStamp -gt $cutoffDate) -and (OperatingSystem -like $searchPattern) } -Properties ipv4Address, OperatingSystem, LastLogonTimeStamp ` -ErrorAction Stop } Write-TimestampedMessage "Found $($allComputers.Count) matching computers." if ($allComputers.Count -eq 0) { Write-Progress -Activity 'Querying Active Directory' -Status 'No hosts found. Ending process.' -Completed return } # Process each AD computer to check manageability $totalComputers = $allComputers.Count $count = 0 $results = foreach ($comp in $allComputers) { $count++ $percentComplete = [math]::Round(($count / $totalComputers) * 100) Write-Progress -Activity 'Checking Manageability' -Status "Checking WS-Man access for $($comp.Name)..." -PercentComplete $percentComplete Write-TimestampedMessage "Checking WS-Man access for $($comp.Name)" $testRemoting = Test-WSMan -ComputerName $comp.Name -ErrorAction SilentlyContinue [PSCustomObject]@{ ComputerName = $comp.Name IPAddress = $comp.IPv4Address OperatingSystem = $comp.OperatingSystem LastLogonTimeStamp = [DateTime]::FromFileTime($comp.LastLogonTimeStamp) IsRemotable = $null -ne $testRemoting } } Write-Progress -Activity 'Checking Manageability' -Status 'Completed manageability check.' -Completed } catch { Write-Progress -Activity 'Checking Manageability' -Status 'Error encountered. See logs.' -Completed throw "Error retrieving AD computers: $($_.Exception.Message)" } } else { Write-TimestampedMessage 'Operation canceled by ShouldProcess.' } } end { Write-Progress -Activity 'Finalizing' -Status 'Returning results...' -PercentComplete 100 -Completed return $results } } #EndRegion '.\Public\Get-ADHostManageability.ps1' 123 |