Archive for the ‘My Best’ Category

Update GPOs with Newer Version

Wednesday, March 1st, 2017

If you use GPOs to enforce baselines, you may find that your enterprise is moving from version 1.1 to version 1.2 of a GPO.  Unfortunately for you, version 1.1 linked in a dozen places.  Wouldn’t you rather just you search for version 1.1 and replace it with version 1.2?  Use Update-GPOLinks.ps1 to do just that.  The script not only finds all the original links and updates them to the new version, it also keeps the link order.

Script Text

Remove Active Directory Delegations

Saturday, February 25th, 2017

Over time, Active Directory delegations tend to accumulate and drift from the standards in the enterprise.  Removing the delegations for a user or group can be slow, especially if you do it manually.  Microsoft has a good article about this process, but none of the methods I found did what I needed.  I wanted a script which could look at all or selected OUs in AD for a delegation, and then delete them all.

Remove-DelegatedOUPermissions.ps1 is an advanced function which can be used to report and remove assigned delegated permissions from OU objects and containers.  You can choose the domain and searchbase, and you can search for full name or partial matches.  For example, if you wanted to report on or delete the delegations for Site1PWAdmins and Site2PWAdmins, you could simply specify “PWAdmins”.  The search is case-insensitive, and you can search for more than one string by separating your search terms with a comma.

This function always creates a log file.  The default name is derived from the domain name, and the default location is the desktop.  The function requires the ActiveDirectory module, but unlike Set-ACL, it can be used to write permissions in another domain.  It supports WhatIf, and a confirmation is required before you commit changes.  Because it is an advanced function, you can use Get-Help for details about use.

Script Text

Quickly Check Domain Controller Health

Monday, September 5th, 2016

How can you tell whether an Active Directory domain controller is functioning properly?  How do you know whether some over-zealous VLAN ACL is blocking necessary ports?  Testing ICMP, is easy, just ping it.  Testing LDAP response isn’t hard, I wrote a vbScript to do that years ago.  But to complete, we want to check more.  My list of things to check are this:

  • Ping
  • TCP Ports 53,88,135,389,445,464
  • UDP Ports 53,389,464
  • If you are running NetBIOS add 139 TCP and UDP ports 137,138
  • If the DNS port is open run NSLookup to check lookups
  • If LDAP port is open, do a test bind

Since a large enterprise may have a large number of DCs, I wanted to multi-thread the script.  For compatibility, I wanted to be able to run it on PowerShell 3 from a Windows 7 host without admin rights.

What I discovered is that testing TCP ports with PowerShell is pretty easy.  UDP connections, however, turned out to be more difficult.  After about 45 minutes of frustration, I found a great Test-Port function from PowerShell MVP Boe Prox.  It is contained inside the script.

In my view, WorkFlows, introduced in Version 3, are the easiest way to multi-thread in PowerShell, and is a way which does not require special setup or rights on the remote systems. On my system, I see about 4 simultaneous queries using this method.

Test-DCs.ps1 can be edited to choose the testing of whatever ports you require and could easily be changed to test other systems such as web servers, Exchange or SharePoint servers.

Update 10-1-19:  This version has many improvements, including multi-threading and dynamically determining whether query of DNS or GC ports is required.

Script Text

A GUI to Select Object Properties in Pipeline

Saturday, May 14th, 2016

My first attempt at a GUI to select objects properties demonstrated that I didn’t have a firm grasp on how to pipeline an object through an advanced function.  The problem I had at the time was not understanding how to have the form only appear once.  Why is that difficult?  Because the Begin Block won’t accept an variable created as an argument to the function.  If you put the form block into the Process Block, you get it popping up once for each item in the pipeline.  The desired result is to run the form just once.  The solution in my new version of Select-PropertyForm.ps1 is to create a variable to cause the form to be created only one time:

Note from above that $script:NewList is a list of the selected properties.  The selection form looks just like the previous version:

I have added a parameter to the function to set the title.  This has been changed to a full advanced function.  You must include it in your own code or “dot source” it to run.

An example:

This user the Get-User AD cmdlet to get all users with the last name of “Smith”, returning AD properties.  I then pipe to Convert-ADValues to ensure that dates and other values export okay, send results to CSV file.  The output for this is  Selected.Microsoft.ActiveDirectory.Management.ADUser

Script Text

Fast PowerShell Treeview OU Selection Form

Thursday, April 28th, 2016

A large number of my scripts involve picking an Active Directory Organizational Unit (OU). I have been using Out-Gridview for OU navigation, such as found in OUADSPath2Clip.ps1. This is because I have been unable to find a form based GUI OU picker that worked fast enough in my very large AD environment.  The one’s I have seen tended to collect all objects at once, and are very slow to load.  Now that I have been working with PowerShell for nearly three years, I decided it was time to give in another try.  The result of my efforts is Select-ADOU.ps1.

This PowerShell script begins by finding the AD Forest, and enumerating all domains.  The user’s current domain is set as the default, and the first level of the domain is automatically expanded and put into the TreeView.  This expansion of the first level is done with any domain selected.  Double click on an node to expand the list of OU below the branch.  The script uses the [adisiSearcher] accelerator with a OneLevel query of “(ObjectCategory=OrganizationalUnit)”  — the ActiveDirectory module does not need to be loaded for it to work.  When the OU is selected, the function returns an object which contains the DNS domain name and the OUs distinguishedname attributes.  This makes it easy to use the information in subsequent code. Version 1.1 allows control of form and button text.
Script Text

Delete Inactive User Profiles with PowerShell

Wednesday, October 16th, 2013

Written to replace DelProf, this script deletes inactive user profiles from a local or remote computer.  It supports arguments by position, and has a test parameter.  If you run it locally, you may supply host name, localhost or “.” The logfile is tab delimited, you may use XLS extension to open in Excel.  If you run the script interactively the log opens when the action is complete.  This is written to be loaded with “dot sourcing”, ex:
. "c:\mypsscripts\Delete-InactiveProfiles.ps1"

After you have loaded the module you can use Get-Help Delete-InactiveProfiles.ps1 for more information on syntax.

Delete-InactiveProfiles.ps1 is heavily commented so you can see what it is doing.  I am using WMI to get the list of local users, and query NTUser.DAT for last logon time.  Remember to rename from Delete-InactiveProfiles_ps1.txt to Delete-InactiveProfiles.ps1.

Convert data from Get-ADUser and Get-ADComputer for Export-CSV

Saturday, July 27th, 2013

If you have been following my blog, you know that I am an experienced vbscripter, but am relatively new to PowerShell.  I was excited that my long vbscripts to export data from Active Directory would be now one liners which I could send to a CSV file with the Export-CSV cmdlet.   Unfortunately, I found that getting the data I wanted was not as easy as I expected.  There is no automatic way of handling the different date strings in Active Directory.  And, although some of the data looked okay when output to the screen, values stored other than a simple string often gave me results like “Microsoft.ActiveDirectory.Management.ADPropertyValueCollection”.

Because of these issues, I set out to create my first PowerShell function.  My goals were to write something that I could use every day which would take the output of Get-ADUser,  Get-ADComputer and other Get-AD* cmdlets within the ActiveDirectory module and convert the data to strings which would properly output to Export-CSV.  As far as I can tell from my internet search, no one has written such a PowerShell function.   And, of course, the best way to learn a new programming language is to have a real project instead of just exercises.

I had some help with direction by the Scripting Guy himself, Ed Wilson.  I have been truly fortunate to be a member of a PowerShell user group with him as a member and regular speaker.  (For more about Ed and the group, read my previous post.)  Some of my discussion with Ed led to Scripting Guy articles about Active Directory and Export-CSV. Some of the code he sent me prior to the publication of these articles sent me on the right track to create Convert-ADValues.ps1.

Convert-ADValues pre-processes the output of the AD cmdlets, such as Get-ADUser and Get-ADComputer so that the output works with Export-CSV.  All dates appear properly.  ProxyAddresses and PostalAddress appear properly.  Binary data appears a a comma delimited string.

Example 1:
$u = Get-ADUser -Filter {surname -eq “smith”} -properties *
Convert-ADValues $u

Example 2:
$u = Get-ADUser -Filter {surname -eq “smith”} -properties *
$u | Convert-ADValues | Export-CSV -notypeInformation -Path $env:userprofile\desktop\ADInfo.csv

Example 3:
Get-ADComputer -Identity $env:COMPUTERNAME -Properties * |Convert-ADValues

To learn about running scripts and “dot sourcing”, examine the basics here.  I hope the comments within the script are adequate to explain what is being done.  Don’t hesitate to comment or email me with questions.

Updated 8-6-13. I fixed handling of binary, null and empty values, arrays in item, and changed delimiter to semi-colon for values with commas.  And yes, it isn’t pretty.
Updated 1/1/14. I added a switch for enumerating ACLs for the nTSecurityDescriptor attribute, changed names of variables away from users, improved comment based help.
Updated 1/2/14   Removed write-host of Security type added while debugging. Added Online Help.  Moved Load-Module ActiveDirectory to Begin statement, clarified Help to make clear that you must return nTSecurityDescriptor for it to be expanded with -GetSecurity. Removed return of PropertyNames and PropertyCount unless you use ReportPropertyNamesAndCount parameter. Changed output type to PSObject from Array. Added Requires statement for Version 3.

Script Text

USB Monitor for Removable Drives

Wednesday, April 7th, 2010

Having users plug USB drives into their systems can be a portal for malware into your network and data exiting from your network.  There are sophisticated programs that allow you to block and monitor endpoint security, such as Lumension’s Sanctuary.  If you don’t have that in your budget, you can still monitor and detect insertion of USB drives onto your computers.  USBMonitor.vbs is a highly configurable script that can send you email alerts when a user inserts a drive.  The alert will have the user’s name, the device they inserted and the time it happened.  The script can also generate an annoying beep that persists as long as the drive is inserted.  Users get a pop-up window with a message telling them to remove the drive.  You can permit certain devices to be used by all users, by all users at a certain workstation, or by a single user.  This way you can say that Bob can use a camera, or all users may use an approved IronKey.

Email is sent to the administrator via SMTP.  Take time to read the comments, which should guide you to the required edits for this to work in your environment.   Version 4 (4/7/10) adds options for exiting the program for servers and administrators, and reporting if endpoint security software is working.  It also can dismount the drive using the freeware USB Disk Ejector program, which may be downloaded here:  If you need assistance implementing this in your environment, send me an email.

Tags: USB+Monitor