I am attempting to ouput some data Im pulling from ActiveDirectory into a CSV but the output is not what I am expecting. How do I export these hashtables value into a CSV? I have no doubt there is a simple answer to this but my google fu seems to be failing me today.
foreach ($user in $user_data)
{
#{ name = 'DisplayName'; expression = { $user.DisplayName } },
#{ name = 'Email'; expression = { $user.EmailAddress } },
#{ name = 'AccountName'; expression = { $user.SamAccountName } },
#{ name = 'Description'; expression = { $user.Description } },
#{ name = "PasswordLastSet"; expression = { [datetime]::FromFileTime($user.pwdLastSet) } },
#{ name = 'Staff Number'; expression = { $user.pager } },
#{ name = 'LastBadPasswordAttempt'; expression = { $user.LastBadPasswordAttempt } },
#{ name = 'LastLogonDate'; expression = { $user.LastLogonDate } },
#{ name = 'logonCount'; expression = { $user.logonCount } },
#{ name = 'Enabled'; expression = { $user.Enabled } } |
Export-Csv $path2 -Append -NoTypeInformation
}
Since you are using calculated properties syntax, you can simply just use Select-Object rather than looping:
$user_data | Select-Object #{ name = 'DisplayName'; expression = { $_.DisplayName } },
#{ name = 'Email'; expression = { $_.EmailAddress } },
#{ name = 'AccountName'; expression = { $_.SamAccountName } },
#{ name = 'Description'; expression = { $_.Description } },
#{ name = "PasswordLastSet"; expression = { [datetime]::FromFileTime($_.pwdLastSet) } },
#{ name = 'Staff Number'; expression = { $_.pager } },
#{ name = 'LastBadPasswordAttempt'; expression = { $_.LastBadPasswordAttempt } },
#{ name = 'LastLogonDate'; expression = { $_.LastLogonDate } },
#{ name = 'logonCount'; expression = { $_.logonCount } },
#{ name = 'Enabled'; expression = { $_.Enabled } } |
Export-Csv $path2 -NoTypeInformation
For the output you want, I guess it would be better to use an array of custom objects.
$users = #()
ForEach($user in $user_data)
{
$users += New-Object PSObject -Property #{
DisplayName = [String]$user.DisplayName;
Email = [String]$user.EmailAddress;
AccountName = [String]$user.SamAccountName;
Description = [String]$user.Description;
PasswordLastSet = [datetime]::FromFileTime($user.pwdLastSet);
StaffNumber = [String]$user.pager;
LastBadPasswordAttempt = [datetime]::FromFileTime($user.LastBadPasswordAttempt);
LastLogonDate = [datetime]::FromFileTime($user.LastLogonDate);
logonCount = [Int]$user.logonCount;
Enabled = [Bool]$user.Enabled;
}
}
$users | Export-Csv -Path $path2 -NoTypeInformation
Related
Suppose you have the following function:
Function Test-Function {
Param (
[String[]]$ComputerNames = #($env:COMPUTERNAME, 'PC2'),
[String]$PaperSize = 'A4'
)
}
Get-DefaultParameterValuesHC -Path 'Test-Function'
Now to get the default values in the function arguments one can use AST:
Function Get-DefaultParameterValuesHC {
[OutputType([hashtable])]
Param (
[Parameter(Mandatory)]$Path
)
$ast = (Get-Command $Path).ScriptBlock.Ast
$selectParams = #{
Property = #{
Name = 'Name';
Expression = { $_.Name.VariablePath.UserPath }
},
#{
Name = 'Value';
Expression = { $_.DefaultValue.Extent.Text -replace "`"|'" }
}
}
$result = #{ }
$defaultValueParameters = #($ast.FindAll( {
$args[0] -is [System.Management.Automation.Language.ParameterAst] }
, $true) |
Where-Object { $_.DefaultValue } |
Select-Object #selectParams)
foreach ($d in $defaultValueParameters) {
$result[$d.Name] = foreach ($value in $d.Value) {
$ExecutionContext.InvokeCommand.ExpandString($value)
}
}
$result
}
The issue here is that the argument for $ComputerNames is read as a string while it is actually an array of string.
Is there a way that PowerShell can covnert a string to an array? Or even better, read the value correctly in the first place?
You need to look deeper into the AST structure...
I recommend you to play around with this PowerShell: AST Explorer GUI:
For your specific example:
Function Test-Function {
Param (
[String[]]$ComputerNames = #($env:COMPUTERNAME, 'PC2'),
[String]$PaperSize = 'A4'
)
}
$FunctionDefinitionAst = (Get-Command 'Test-Function').ScriptBlock.Ast
$Body = $FunctionDefinitionAst.Body
$ParamBlock = $Body.ParamBlock
$CNParameter = $ParamBlock.Parameters | Where-Object { $_.Name.VariablePath.UserPath -eq 'ComputerNames' }
$DefaultValue = $CNParameter.DefaultValue
$DefaultValue.SubExpression.Statements.PipelineElements.Expression.Elements
VariablePath : env:COMPUTERNAME
Splatted : False
StaticType : System.Object
Extent : $env:COMPUTERNAME
Parent : $env:COMPUTERNAME, 'PC2'
StringConstantType : SingleQuoted
Value : PC2
StaticType : System.String
Extent : 'PC2'
Parent : $env:COMPUTERNAME, 'PC2'
It's a bit of a hackish solution but this is what I came up with to solve the issue of not returning an array of string:
Function Get-DefaultParameterValuesHC {
Param (
[Parameter(Mandatory)]$Path
)
$ast = (Get-Command $Path).ScriptBlock.Ast
$selectParams = #{
Property = #{
Name = 'Name';
Expression = { $_.Name.VariablePath.UserPath }
},
#{
Name = 'Value';
Expression = {
if ($_.DefaultValue.StaticType.BaseType.Name -eq 'Array') {
$_.DefaultValue.SubExpression.Extent.Text -split ',' |
ForEach-Object { $_.trim() -replace "`"|'" }
}
else {
$_.DefaultValue.Extent.Text -replace "`"|'"
}
}
}
}
$result = #{ }
$defaultValueParameters = #($ast.FindAll( {
$args[0] -is [System.Management.Automation.Language.ParameterAst] }
, $true) |
Where-Object { $_.DefaultValue } |
Select-Object #selectParams)
foreach ($d in $defaultValueParameters) {
$result[$d.Name] = foreach ($value in $d.Value) {
$ExecutionContext.InvokeCommand.ExpandString($value)
}
}
$result
}
ExpandPath will only expand variables inside strings. To get the actual values (and not just the definition) you could use Invoke-Expression:
function Get-DefaultParameterValuesHC {
[OutputType([hashtable])]
Param (
[Parameter(Mandatory)]$Path
)
$result = #{ }
(Get-Command $Path).ScriptBlock.Ast.Body.ParamBlock.Parameters | where {$_.DefaultValue} | foreach {
$result[$_.Name.VariablePath.UserPath] = Invoke-Expression $_.DefaultValue.Extent.Text
}
$result
}
NOTE: This will actually invoke the default declaration, so any logic inside that expression will be run, just as when running the function. For example, a default value of $Parameter = (Get-Date) will always invoke Get-Date.
It would be preferable to create a function, that only returns the default declarations, and let the user decide to invoke the expression or not:
function Get-DefaultParameterDeclarations {
Param (
[Parameter(Mandatory, Position = 0)]
[string]$CommandName
)
(Get-Command $CommandName).ScriptBlock.Ast.Body.ParamBlock.Parameters | where {$_.DefaultValue} |
foreach {
[PSCustomObject]#{
Name = $_.Name.VariablePath.UserPath
Expression = $_.DefaultValue.Extent.Text
}
}
}
# get the declarations and (optionally) invoke the expressions:
Get-DefaultParameterDeclarations 'Test-Function' |
select Name, #{n="DefaultValue"; e={Invoke-Expression $_.Expression}}
I created a report, if I run it manually from Powershell ISE, it generates the list of items I am expecting, but when I run it from Reporting Tools it returns no results.
The script scrapes all the items versions and languages, which are around 80,000 items and this takes a while.
Is there a way to add a delay until the list of all items is generated, or any other workaround ?
Source code:
$RichTextContentID = "";
$internalLinkPattern = '<a href="~\/link\.aspx\?_id=(?<sitecoreid>[a-zA-Z\d]{32})&_z=z">';
$literatureTemplate = "";
$global:guiltyItems = #();
function Process-RichText
{
param( [Parameter(Mandatory = $true)] [Sitecore.Data.Fields.Field]$field,
[Parameter(Mandatory = $true)] [string]$pattern,
[Parameter(Mandatory = $true)] [Sitecore.Data.Items.Item]$item)
$allMatches = [System.Text.RegularExpressions.Regex]::Matches($field.Value,$pattern);
foreach ($match in $allMatches)
{
$currentItem = Get-Item master -Id ([Sitecore.Data.ID]::Parse($match.Groups["sitecoreid"].Value)).Guid;
if ($currentItem.Template.Id -eq $literatureTemplate)
{
if ($global:guiltyItems -notcontains $item)
{
$global:guiltyItems += $item;
}
}
}
}
$allitems = Get-Item master -Query "/sitecore/content/MyWebsiteTree//*" -Language * -Version *;
foreach ($item in $allItems) {
foreach ($field in $item.Fields)
{
if ($field.Id -eq $RichTextContentID -and ($field.Value -match $internalLinkPattern))
{
Process-RichText $field $internalLinkPattern $item;
}
}
}
if ($global:guiltyItems.Count -eq 0) {
Show-Alert "Did not find any items to match your condition.";
}
else {
$props = #{
Title = ""
InfoDescription = ""
PageSize = 50
};
($global:guiltyItems) |
Show-ListView #props -Property #{ Label="Item name"; Expression={$_.Name}; },
#{ Label="ID"; Expression={$_.ID}; },
#{ Label="Display name"; Expression={$_.DisplayName}; },
#{ Label="Language"; Expression={$_.Language}; },
#{ Label="Version"; Expression={$_.Version}; },
#{ Label="Path"; Expression={$_.ItemPath}; },
#{ Label="Created"; Expression={$_.__Created}; },
#{ Label="Created by"; Expression={$_."__Created by"}; },
#{ Label="Updated"; Expression={$_.__Updated}; },
#{ Label="Updated by"; Expression={$_."__Updated by"}; }
}
Close-Window;
Thanks
LE: The object $allitems takes a while to be populated and the sitecore client does not wait for the backend to read all the items, and thus when I generate the report, $global:guiltyItems is always empty.
I have found the solution: using filters. And it works as it should.
$RichTextContentID = "";
$internalLinkPattern = '<a href="~\/link\.aspx\?_id=(?<sitecoreid>[a-zA-Z\d]{32})&_z=z">';
$literatureTemplateID = "";
$root = Get-Item -Path "master:/sitecore/content/MyWebsite";
filter Where-HasLiterature{
param([Parameter(Mandatory=$TRUE,ValueFromPipeline=$TRUE)][Sitecore.Data.Items.Item]$item)
if($item)
{
foreach ($field in $item.Fields)
{
if ($field.Id -eq $RichTextContentID -and ($field.Value -match $internalLinkPattern))
{
$allMatches = [System.Text.RegularExpressions.Regex]::Matches($field.Value,$internalLinkPattern);
foreach ($match in $allMatches)
{
$guiltyItem = Get-Item "master:" -Id ([Sitecore.Data.ID]::Parse($match.Groups["sitecoreid"].Value)).Guid;
$guiltyItemTemplate = [Sitecore.Data.Managers.TemplateManager]::GetTemplate($guiltyItem);
if ($guiltyItem -ne $null -and $guiltyItemTemplate.DescendsFromOrEquals($literatureTemplateID) )
{
$item;
}
}
}
}
}
}
$items = Get-ChildItem -Path $root.ProviderPath -Recurse | Where-HasLiterature
if ($items.Count -eq 0)
{
Show-Alert "Did not find any items to match your condition.";
}
else
{
$props = #{
Title = ""
InfoDescription = ""
PageSize = 50
}
$items | Show-ListView #props -Property #{ Label="Item name"; Expression={$_.Name}; },
#{ Label="ID"; Expression={$_.ID}; },
#{ Label="Display name"; Expression={$_.DisplayName}; },
#{ Label="Language"; Expression={$_.Language}; },
#{ Label="Version"; Expression={$_.Version}; },
#{ Label="Path"; Expression={$_.ItemPath}; },
#{ Label="Created"; Expression={$_.__Created}; },
#{ Label="Created by"; Expression={$_."__Created by"}; },
#{ Label="Updated"; Expression={$_.__Updated}; },
#{ Label="Updated by"; Expression={$_."__Updated by"}; }
}
So currently, I know you can grab an account using the ldap filter for something like $adSearchFilter = "(&(objectCategory=User)(samAccountType:1.2.840.113556.1.4.803:=805306368)(SamAccountName='Account1')). Is there a way the ldap filter will allow you to pass through a list of names, like instead of using = I can use something like -contains?
Below is the code, and as you can see, it searches one user at a time for the whole search process in a foreach loop...
Function GetUsersInfoFromDomain
{
Param ([String]$searchPropertyName, [String[]]$searchPropertyValues, [String[]]$DcWithCred,[String]$domainShortName, [String[]]$userProperties)
$queryTable = #()
ForEach ($searchPropertyValue in $searchPropertyValues)
{
$adSearchFilter = "(&(objectCategory=User)(samAccountType:1.2.840.113556.1.4.803:=805306368)($searchPropertyName=$searchPropertyValue))"
Write-Host "Searching domain $domainShortName with $searchPropertyName $searchPropertyValue"
$searchDomainResultsTable = powershell -command {
Param ([String]$adSearchFilter, [String[]]$userProperties,[String[]]$DcWithCred, [String]$domainShortName)
[string]$DC = $DcWithCred[0]
[string]$Username = $DcWithCred[1]
[string]$Password = $DcWithCred[2]
[string]$domain = "LDAP://$DC"
$adDomain = New-Object System.DirectoryServices.DirectoryEntry($domain, $Username, $Password)
$adSearcher = New-Object System.DirectoryServices.DirectorySearcher($adDomain)
$adSearcher.Filter = $adSearchFilter
$adSearcher.PageSize=1000
$adSearcher.PropertiesToLoad.AddRange($userProperties) | out-Null
$userRecords = $adSearcher.FindAll()
$adSearcher.Dispose() | Out-Null
[System.GC]::Collect() | Out-Null
# The AD results are converted to an array of hashtables.
$userPropertiesTable = #()
foreach($record in $userRecords) {
$hashUserProperty = #{}
foreach($userProperty in $userProperties){
if (($userProperty -eq 'objectGUID') -or ($userProperty -eq 'objectSid') -or ($userProperty -eq 'msExchMasterAccountSid')) {
if ($record.Properties[$userProperty]) {
$hashUserProperty.$userProperty = $record.Properties[$userProperty][0]
} else {
$hashUserProperty.$userProperty = $null
}
} Else {
if ($record.Properties[$userProperty]) {
$hashUserProperty.$userProperty = ($record.Properties[$userProperty] -join '; ').trim('; ')
} else {
$hashUserProperty.$userProperty = $null
}
} #end Else
} #end ForEach
$userPropertiesTable += New-Object PSObject -Property $hashUserProperty
} #end ForEach
[System.GC]::Collect() | Out-Null
# Fixes the property values to be a readable format before exporting to csv file
$listOfBadDateValues = '9223372036854775807', '9223372036854770000', '0'
$maxDateValue = '12/31/1600 5:00 PM'
$valuesToFix = #('lastLogonTimestamp', 'AccountExpires', 'LastLogon', 'pwdLastSet', 'objectGUID', 'objectSid', 'msExchMasterAccountSid')
$extraPropertyValues = #('Domain Name')
$valuesToFixCounter = 0
$extraPropertyValuesCounter = 0
$valuesToFixFound = #($false, $false, $false, $false, $false, $false, $false)
$extraPropertyValuesFound = #($false)
ForEach ($valueToFix in $valuesToFix)
{
if ($userProperties -contains $valueToFix)
{
$valuesToFixFound[$valuesToFixCounter] = $true
}
$valuesToFixCounter++
}
ForEach ($extraPropertyValue in $extraPropertyValues)
{
if ($userProperties -contains $extraPropertyValue)
{
$extraPropertyValuesFound[$extraPropertyValuesCounter] = $true
}
$extraPropertyValuesCounter++
}
$tableFixedValues = $userPropertiesTable | % {
if ($valuesToFixFound[0]) {
if ($_.lastLogonTimestamp) {
$_.lastLogonTimestamp = ([datetime]::FromFileTime($_.lastLogonTimestamp)).ToString('g')
}
}; if ($valuesToFixFound[1]) {
if (($_.AccountExpires) -and ($listOfBadDateValues -contains $_.AccountExpires)) {
$_.AccountExpires = ""
} else {
if (([datetime]::FromFileTime($_.AccountExpires)).ToString('g') -eq $maxDateValue) {
$_.AccountExpires = ""
} Else {
$_.AccountExpires = ([datetime]::FromFileTime($_.AccountExpires)).ToString('g')
}
}
}; if ($valuesToFixFound[2]) {
if (($_.LastLogon) -and ($listOfBadDateValues -contains $_.LastLogon)) {
$_.LastLogon = ""
} else {
if (([datetime]::FromFileTime($_.LastLogon)).ToString('g') -eq $maxDateValue) {
$_.LastLogon = ""
} Else {
$_.LastLogon = ([datetime]::FromFileTime($_.LastLogon)).ToString('g')
}
}
}; if ($valuesToFixFound[3]) {
if (($_.pwdLastSet) -and ($listOfBadDateValues -contains $_.pwdLastSet)) {
$_.pwdLastSet = ""
} else {
if (([datetime]::FromFileTime($_.pwdLastSet)).ToString('g') -eq $maxDateValue) {
$_.pwdLastSet = ""
} Else {
$_.pwdLastSet = ([datetime]::FromFileTime($_.pwdLastSet)).ToString('g')
}
}
}; if ($valuesToFixFound[4]) {
if ($_.objectGUID) {
$_.objectGUID = ([guid]$_.objectGUID).Guid
} Else {
$_.objectGUID = ""
}
}; if ($valuesToFixFound[5]) {
if ($_.objectSid) {
$_.objectSid = (New-Object Security.Principal.SecurityIdentifier($_.objectSid, 0)).Value
} Else {
$_.objectSid = ""
}
}; if ($valuesToFixFound[6]) {
if ($_.msExchMasterAccountSid) {
$_.msExchMasterAccountSid = (New-Object Security.Principal.SecurityIdentifier($_.msExchMasterAccountSid, 0)).Value
} Else {
$_.msExchMasterAccountSid = ""
}
}; If ($extraPropertyValuesFound[0]) {
If (!($_.'Domain Name')) {
$_.'Domain Name' = $domainShortName
}
};$_}
[System.GC]::Collect() | Out-Null
$sortedTableColumns = $tableFixedValues | Select-Object $userProperties
[System.GC]::Collect() | Out-Null
return $sortedTableColumns
} -args $adSearchFilter, $userProperties, $DcWithCred, $domainShortName
[System.GC]::Collect() | Out-Null
Write-Host "Search Complete."
Write-Host ""
if ($searchDomainResultsTable)
{
$queryTable += $searchDomainResultsTable
}
} # End ForEach Loop
Write-Host 'Exporting domain search results to table...'
Write-Output $queryTable
}
I thought about doing something like $adSearchFilter += "($searchPropertyName=$searchPropertyValue)". However due to the 10mb limit - What is the LDAP filter string length limit in Active Directory?, I'm not sure if this would be the best method while looking up 200,000++ users.
Does anyone know a way to pass a list instead of 1 string value per search?
LDAP doesn't have a -contains-like statement, but you can use the OR operator (|) to construct a filter expression that matches multiple exact values:
(|(samaccountname=user1)(samaccountname=user2)(samaccountname=user3))
This is how I would build the filter string:
$FilterTemplate = '(&(objectCategory=User)(samAccountType:1.2.840.113556.1.4.803:=805306368){0})'
$ClauseTemplate = "($searchPropertyName={0})"
$AllClauses = $searchPropertyValues |ForEach-Object { $ClauseTemplate -f $_ }
$adSearchFilter = $FilterTemplate -f $($AllClauses -join '')
That being said, why would you pass 200000 specific values to search for in a single search? LDAP supports wildcard matching (eg. (samaccountname=*)).
In any case, you could calculate the final size of your string, by calling Encoding.GetByteCount on the biggest string in $AllClauses, and then use that to partition the array (let's cap it at 9.5 MB to be on the safe side):
$LongestString = $AllClauses |Sort -Property Length |Select -Last 1
$LongestByteCount = [System.Text.Encoding]::Unicode.GetByteCount($LongestString)
if(($LongestByteCount * $AllClauses.Count) -gt 9.5MB)
{
$MaxCount = [int](9.5MB / $LongestByteCount)
for($i = 0; $i -lt $AllClauses.Count; $i += $MaxCount)
{
$ClauseSubset = $AllClauses[$i..$($i + $MaxCount - 1)]
$adSearchFilter = $FilterTemplate -f $($ClauseSubset -join '')
# Do your search
}
}
I have this code in PowerShell that looks into groups and users and creates a tab delimited txt file with the fields that I want.
However it only finds half of the information. I am trying to replace another process that generates an identical report and this report gathers around 580,000 lines of data where as this PowerShell report only generates around 300,000.
I think I need to look into groups recursively, but I'm not sure how to do that.
code:
#requires -version 2
$ScriptName = $MyInvocation.MyCommand.Name
$ADS_GROUP_TYPE_SECURITY_ENABLED = 0x80000000
$PageSize = 250 # Adjust as needed
# Create the Pathname object and enable its EscapedMode property
$ADS_ESCAPEDMODE_ON = 2
$ADS_SETTYPE_DN = 4
$ADS_FORMAT_X500_DN = 7
$Pathname = new-object -comobject "Pathname"
[Void] $Pathname.GetType().InvokeMember("EscapedMode", "SetProperty", $NULL, $Pathname, $ADS_ESCAPEDMODE_ON)
# Returns correctly escaped DN using Pathname object
function Get-EscapedPath {
param(
[String] $distinguishedName
)
[Void] $Pathname.GetType().InvokeMember("Set", "InvokeMethod", $NULL, $Pathname, ($distinguishedName, $ADS_SETTYPE_DN))
$Pathname.GetType().InvokeMember("Retrieve", "InvokeMethod", $NULL, $Pathname, $ADS_FORMAT_X500_DN)
}
# Returns a property from a ResultPropertyCollection if it's defined
function Get-SearchResultProperty {
param(
[System.DirectoryServices.ResultPropertyCollection] $properties,
[String] $propertyName
)
if ( $properties[$propertyName] ) {
$properties[$propertyName][0]
}
else {
""
}
}
# Returns a property from a DirectoryEntry if it's defined
function Get-DirEntryProperty {
param(
[System.DirectoryServices.DirectoryEntry] $dirEntry,
[String] $propertyName
)
if ( $dirEntry.$propertyName ) {
$dirEntry.$propertyName[0]
}
else {
""
}
}
write-progress $ScriptName "Enumerating groups"
$domain = [ADSI] ""
$searcher = [ADSISearcher] "(objectClass=group)"
$searcher.SearchRoot = $domain
$searcher.PageSize = $PageSize
$searcher.SearchScope = "subtree";
$searcher.PropertiesToLoad.AddRange(#("name","grouptype","distinguishedname","description","managedby","member"))
$searchResults = $searcher.FindAll()
$groupCounter = 0
$groupCount = $searchResults.Count
foreach ( $searchResult in $searchResults ) {
$properties = $searchResult.Properties
$domainName = "domainname"
$groupName = Get-SearchResultProperty $properties "name"
$groupType = Get-SearchResultProperty $properties "grouptype"
if ( ($groupType -band $ADS_GROUP_TYPE_SECURITY_ENABLED) -ne 0 ) {
$groupTypeString = "Security"
}
else {
$groupTypeString = "Distribution"
}
$groupDescription = Get-SearchResultProperty $properties "description"
$groupDN = Get-SearchResultProperty $properties "distinguishedname"
$groupManagedBy = Get-SearchResultProperty $properties "managedby"
$member = $properties["member"]
if ( $member ) {
$memberCounter = 0
$memberCount = ($member | measure-object).Count
foreach ( $memberDN in $member ) {
$memberDirEntry = [ADSI] "LDAP://$(Get-EscapedPath $memberDN)"
"" | select-object `
#{Name = "Domain"; Expression = {$domainName}},
#{Name = "Group Name"; Expression = {$groupName}},
#{Name = "Type"; Expression = {$groupTypeString}},
#{Name = "Description"; Expression = {$groupDescription}},
#{Name = "Distinguished Name"; Expression = {$groupDN}},
#{Name = "Managed By"; Expression = {$groupManagedBy}},
#{Name = "Members"; Expression = {$memberDN}},
#{Name = "Full Name"; Expression = {Get-DirEntryProperty $memberDirEntry "name"}},
#{Name = "User Name"; Expression = {Get-DirEntryProperty $memberDirEntry "samaccountname"}},
#{Name = "Display Name"; Expression = {Get-DirEntryProperty $memberDirEntry "displayname"}}
$memberCounter++
$memberPercent = ($memberCounter / $memberCount) * 100 -as [Int]
$params = #{
"Activity" = $ScriptName
"Completed" = $memberPercent -eq 100
"CurrentOperation" = "Enumerating '$groupDN'"
"PercentComplete" = $memberPercent
"Status" = "Groups: {0}/{1} [{2:P2}] - Members: {3}/{4} [{5:P2}]" -f
$groupCounter,
$groupCount,
($groupCounter / $groupCount),
$memberCounter,
$memberCount,
($memberCounter / $memberCount)
}
write-progress #params
}
}
else {
# Group contains no members
"" | select-object `
#{Name = "Domain"; Expression = {$domainName}},
#{Name = "Group Name"; Expression = {$groupName}},
#{Name = "Type"; Expression = {$groupTypeString}},
#{Name = "Description"; Expression = {$groupDescription}},
#{Name = "Distinguished Name"; Expression = {$groupDN}},
#{Name = "Managed By"; Expression = {$groupManagedBy}},
#{Name = "Members"; Expression = {""}},
#{Name = "Full Name"; Expression = {""}},
#{Name = "User Name"; Expression = {""}},
#{Name = "Display Name"; Expression = {""}}
}
$groupCounter++
$groupPercent = ($groupCounter / $groupCount) * 100 -as [Int]
$params = #{
"Activity" = $ScriptName
"Completed" = $groupPercent -eq 100
"CurrentOperation" = "Enumerating '$groupDN'"
"PercentComplete" = $groupPercent
"Status" = "Groups: {0}/{1} [{2:P2}]" -f
$groupCounter,
$groupCount,
($groupCounter / $groupCount)
}
write-progress #params
# Periodically force garbage collection to reduce memory usage
if ( ($groupCounter % $PageSize) -eq 0 ) {
[GC]::Collect()
[GC]::WaitForPendingFinalizers()
}
}
$searchResults.Dispose()
EDIT:
I have tried using this line, just before the line containing "subtree":
$searcher.Filter = "(member:1.2.840.113556.1.4.1941:=*)"
and tried editing this line:
$searcher = [ADSISearcher] "(objectClass=group)"
to this
$searcher = [ADSISearcher] "(&(objectClass=group)(memberof:1.2.840.113556.1.4.1941L:=*))"
Neither work, it just returns immediately with no output, presumably as the filter is not picking up anything. I didn't have a filter before because I wanted everything
There's an LDAP filter (1.2.840.113556.1.4.1941) for that:
LDAP Matching Rule in Chain
i want to format as table an Array of PSObject my code is:
$object = #()
Foreach ($Alarm in Get-AlarmDefinition) {
Foreach ($AlarmAction in Get-AlarmAction -AlarmDefinition $Alarm) {
$obj = New-Object PSObject -property #{Definition = $Alarm.Name; Action =""; GY=""; YR=""; RY=""; YG=""}
Foreach ($AlarmActionTrigger in Get-AlarmActionTrigger -AlarmAction $AlarmAction) {
$obj.Action = $AlarmAction.ActionType
If ($AlarmActionTrigger.StartStatus -eq "Green") {
$obj.GY = $AlarmActionTrigger.Repeat
} Else {
If($AlarmActionTrigger.StartStatus -eq "Red") {
$obj.RY = $AlarmActionTrigger.Repeat
} Else {
If ($AlarmActionTrigger.EndStatus -eq "Green") {
$obj.YG = $AlarmActionTrigger.Repeat
} Else {
$obj.YR = $AlarmActionTrigger.Repeat
}
}
}
}
$object += $obj
}
}
$object | Format-Table Definition, Action,GY,YR,RY,YG -auto
But returns this error:
ConsoleLineOutputOutOfSequencePacket,Microsoft.PowerShell.Commands.OutLineOutputCommand
Can some please Help?
TNX
You may want to try setting up the format for the table before you call the "Format-Table"
Like this:
$myformat = #{Expression={$_.*one*};Label="*name*";width=10},
#{Expression={$_.*two*};Label="*Two*";width=50},
$Result = $object | Format-Table $myformat -Wrap | Out-String
Write-Host $Result
Microsoft's Documentation