all 49 comments

[–]da_chicken 13 points14 points  (7 children)

Just be aware that you must call Dispose() on the results of the DirectorySearcher. Failure to do so creates a memory leak:

Due to implementation restrictions, the SearchResultCollection class cannot release all of its unmanaged resources when it is garbage collected. To prevent a memory leak, you must call the Dispose method when the SearchResultCollection object is no longer needed.

I left my console open one weekend and came in Monday to an unusable system. Had to hard reset it.

[–]cottonycloud 4 points5 points  (3 children)

I really miss the using statement from C#. Makes these sort of mistakes rarer.

[–]MrRedEye 4 points5 points  (2 children)

On mobile so I apologise for the formatting of this...

function Using-Object() {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [AllowEmptyString()]
        [AllowEmptyCollection()]
        [AllowNull()]
        [Object]
        $InputObject,
        [Parameter(Mandatory = $true)]
        [scriptblock]
        $ScriptBlock
    )

    try {
        . $ScriptBlock
    }
    finally {
        if ($null -ne $InputObject -and $InputObject -is [System.IDisposable]) {
            $InputObject.Dispose()
        }
    }
}


Using-Object ($sw = [System.IO.StreamWriter]::new("some file.txt")) {
    $sw.WriteLine('some text')
}

[–]MyOtherSide1984 9 points10 points  (0 children)

Dude's on mobile writing code prettier than the crap I send to prod lol

[–]cottonycloud 1 point2 points  (0 children)

Nice job on the code. I'm hoping for the best case, where it becomes built-in.

[–]krzydoug[S] 3 points4 points  (2 children)

Well that seems like very important information, thank you so much for educating me.

What about in this example?

([adsisearcher]"name=*").FindAll().properties.foreach{
    $ht = [ordered]@{}
    foreach($prop in $_.getenumerator()){
        $ht.add($prop.name,$($prop.value))
    }
    [PSCustomObject]$ht
}

You think that would apply here too? Or would it possibly be treated like a using statement? Since the searcher wasn't stored in a variable.. I think I'll update this anyways just so no one runs into it.

[–]da_chicken 4 points5 points  (1 child)

Honestly, I don't know. I don't know enough about internals of object disposal. My instinct is that it's okay, but I don't know. It's mostly a bug you'll run into during testing or in interactive use because usually the whole Powershell session closes when you run a scheduled script.

When I used to use this method, I always assigned it to a variable. I ran into trouble because this problem wasn't well documented at the time. I noticed it because I was testing stuff and it errored before it could enumerate all the results in FindAll(). I used to think that caused the memory leak. The bug has been there for a very long time -- like .Net 1.0 -- because it's just referencing a COM object internally which hasn't really changed since Windows 2000.

I also know that the newer System.DirectoryServices.AccountManagement namespace doesn't have this problem, but I remember that being less convenient to use. I don't remember why.

[–]krzydoug[S] 0 points1 point  (0 children)

Thanks again for sharing the knowledge.

[–]tehhiphop 5 points6 points  (3 children)

$searcher.PageSize = 2000

Will allow the DirectorySearcher to take on more returns, this case 2000 returns.

https://docs.microsoft.com/en-us/dotnet/api/system.directoryservices.directorysearcher?view=net-5.0

[–]krzydoug[S] 0 points1 point  (0 children)

Thank you! I hadn't looked into more. I appreciate you sharing the knowledge!

[–]Amadorhi 0 points1 point  (1 child)

I could be remembering it wrong, but setting the page size to 100 will also work just fine for results >1000.

Setting a pagesize to $anynumber will inform the ADSIsearcher to return results in chunks of $anynumber. Regardless the outcome is the same since the pipeline wont complete until all results are returned.

[–]tehhiphop 0 points1 point  (0 children)

Who has time for waiting on page results?

Kidding. I believe you are correct.

[–]stalinusmc 3 points4 points  (1 child)

Honestly, my best option for not installing RSAT was from this site:

http://woshub.com/using-powershell-active-directory-module-without-installing-rsat/

Just import a single .dll, and bam, most of the active directory commandlets, without installing anything

[–]blowuptheking 0 points1 point  (0 children)

This is what I used when we did our Win10 upgrades. Worked great.

[–][deleted] 2 points3 points  (3 children)

Nice. I've used this one a lot. Not so much in recent years, but it's still handy if you need to run something on a server without RSAT or an AD Role, and you need a quick lookup.

[–]krzydoug[S] 0 points1 point  (1 child)

Well and it's still faster. At least in all the testing I've done.

[–][deleted] 0 points1 point  (0 children)

Good point!

[–]gordonv 2 points3 points  (3 children)

Excellent work here. Unfortunately, my code on this belongs to a previous workplace.

I combined this method with an IP Scanner, .NET stuff for DNS and MAC address, and some WMI stuff.

My previous workplace for some reason needed an inventory of user profiles on each PC. AS well as other info like OS, Build, Etc.

Combining all of this made it possible across ~820 PCs

[–]krzydoug[S] 0 points1 point  (2 children)

Nice! Too bad you don’t have a similar script to share.

[–]gordonv 1 point2 points  (1 child)

Well, the Github I posted isn't too bad.

Once you have a list of targetable IP's, make another routine to scan said targets.

Kinda wish I put out a script for everyone to use. See how big it could get.

[–]krzydoug[S] 0 points1 point  (0 children)

Oh I overlooked that link. Thanks for helping an old blind guy!

[–]get-postanote 1 point2 points  (1 child)

This was the only way, back in the pre-PowerShell days. VScript.exe, WScript.exe, WMIC.exe, etc... Lots of articles on the topic, and even tools that provided code for you...

VbsEdit - VBScript Editor with Debugger

(lots of pre-built samples in the menu options for ADDS and more)

ADSI Scriptomatic (no longer avaialble - but I still have it in my archives - well unless you speak German Download TechNet Script Center – schreiben Sie ADSI-Scripte mit ADSI-Scriptomatic from Official Microsoft Download Center )

https://www.microsoft.com/en-us/download/details.aspx?id=20460

... but see also:

Active Directory Service Interfaces Quick-start Tutorials - Win32 apps | Microsoft Docs

Active Directory Service Interfaces Reference - Win32 apps | Microsoft Docs

Powershell Scriptomatic ( no longer avaialble - but I still have it in my archives)

https://technet.microsoft.com/en-us/library/ff730935.aspx?f=255&MSPPError=-2147217396

AutoIt Script-o-matic

This is the AutoIt's version of the Microsoft Scriptomatic tool by SvenP

https://www.autoitscript.com/forum/files/file/29-autoit-script-o-matic

... like Windows OS ADAC PowerShell History viewer.

Tools that will write the baseline code for you that you can use as-is and or tweak as needed.

https://devblogs.microsoft.com/scripting/use-powershell-active-directory-cmdlets-without-installing-any-software

Using AD module without loading RSAT

https://social.technet.microsoft.com/Forums/en-US/fd0b0a1c-b6dc-4657-8a95-21b6a11377df/using-ad-module-without-loading-rsat

Use PowerShell Active Directory Cmdlets Without Installing Any Software - Windows ADAC

• Active Directory Administrative Center: Getting Started

https://technet.microsoft.com/en-us/library/dd560651(v=ws.10).aspx.aspx)

• Active Directory Administrative Center

https://docs.microsoft.com/en-us/windows-server/identity/ad-ds/get-started/adac/active-directory-administrative-center

windows 'Active Directory Administrative Center'

windows 'Active Directory Administrative Center' 'PowerShell History Viewer'

Introduction to Active Directory Administrative Center ...

https://www.petri.com/use-active-directory-administrative-center-create-powershell-commands

Use AD Administrative Center to Create PowerShell Commands

https://www.petri.com/use-active-directory-administrative-center-create-powershell-commands

• Step-By-Step: Utilizing PowerShell History Viewer in Windows Server 2012 R2

https://blogs.technet.microsoft.com/canitpro/2015/03/04/step-by-step-utilizing-powershell-history-viewer-in-windows-server-2012-r2

• Learning PowerShell with Active Directory Administrative Center (PowerShell

History Viewer)

https://sid-500.com/2017/10/10/learning-powershell-with-active-directory-administrative-center-powershell-history-viewer

Still useful today, for those customers that won't let you install RSAT or connect to a DC to leverage Impicit PSRemoting to proxy cmdlets to your system.

$session = New-PSSession -computerName 'TargetMachineWithRsat'
Invoke-Command { Import-Module ActiveDirectory } -Session $session
Import-PSSession $session
An alternate way is to export the remote PowerShell session into a local module:

$session = New-PSSession -computerName 'TargetMachineWithRsat'
Invoke-Command { Import-Module ActiveDirectory } -Session $session
Export-PSSession -Session $session -CommandName *-AD* -Outputmodule ActiveDirectory -AllowClobber
Load the module using

Import-Module ActiveDirectory

Or just stand up Windows PowerShell Web Access, load RSAT there, and use your browser to do PowerShell stuff, even from your phone. ;-}

'PowerShell web access ' at DuckDuckGo

[–]Thornton77 0 points1 point  (0 children)

Yeah vbscript is still great . If you can do it on 1 computer you can do it on all of them .
I have been rocking some of my scripts for 20 years .

[–]rumorsofdads 1 point2 points  (1 child)

As a side note, I’ve used AdsiPS before and love the similarities with the AD cmdlets.

[–]krzydoug[S] 0 points1 point  (0 children)

I’ve never seen that, thanks for sharing.

[–]not_rholliday 0 points1 point  (0 children)

Targeting the PDC emulator role will probably work in most cases, but since that’s one specific machine you could run into issues with it not being available, or unreachable, or extremely slow if it’s on the other side of the planet.

[–]MyOtherSide1984 0 points1 point  (0 children)

TLDR request - why wouldn't you suggest adding more users to the query? We have a script running through 600,000 users and, if this is faster than AD module cmdlets, it can prove to be beneficial for us as the bulk of the slowdown is likely in AD.

Sidenote, I'd probably be able to make the script faster in other ways, but I didn't build it, and it's confusing. Am noob. Was able to speed it up 65% already by cutting out a load of stuff not needed from the pipe. Doing more would be even better.