25 January 2016

PowerShell speed optimizing on Active Directory cmdlets

Lets imagine, you have a task to find some AD user accounts based on a criteria and perform a simple task for each of them. My case is to clear manager for all user accounts, where extensionattribute3 is not present. This needs to be done regularly. So the time spent on this task should be minimized.

Initial version took about 160 seconds to run:

Measure-Command {
$users = Get-ADUser -Filter * -Properties extensionAttribute3 | ? extensionAttribute3 -ne 'Nortal Employee'
$users | foreach {Set-ADUser $_.SamAccountName -Clear manager -WhatIf}
}

Lets try to eliminate users, who already have manager cleared and not clearing the manager for them. This run took about 20 seconds because, instead of thousands of users, only few hundred were actually touched:

Measure-Command {
$users = Get-ADUser -Filter * -Properties manager,extensionAttribute3 | ? extensionAttribute3 -ne 'Nortal Employee' | ? manager
$users | foreach {Set-ADUser $_.SamAccountName -Clear manager -WhatIf}
}

Next iteration would be piping all users directly to Set-ADUser cmdlet, but this would not work straight forward, we will need Select-Object with ExpandProperty. This run took about 5 seconds because Set-ADUser was loaded only once instead of hundred times:

Measure-Command {
$users = Get-ADUser -Filter * -Properties manager,extensionAttribute3 | ? extensionAttribute3 -ne 'Nortal Employee' | ? manager
$users | select -ExpandProperty SamAccountName | Set-ADUser -Clear manager -WhatIf
}

Get-ADUser will still get all users and the filtration is done in PowerShell. This can be optimized to pass LDAP query to AD to return only needed user accounts. This run took about 2 seconds:

Measure-Command {
$users = Get-ADUser -LDAPFilter "(&(manager=*)(!extensionAttribute3=*))"
$users | select -ExpandProperty SamAccountName | Set-ADUser -Clear manager -WhatIf
}

This command can be converted to oneliner. This will have no noticeable effect on command duration, but looks perhaps cleaner:

Measure-Command {Get-ADUser -LDAPFilter "(&(manager=*)(!extensionAttribute3=*))" | select -ExpandProperty SamAccountName | Set-ADUser -Clear manager -WhatIf}

So our initial code was later optimized to to run nearly 100 times faster. Not a bad thing for a scheduled task running daily or hourly.

12 August 2015

Allow a specific port through Windows Firewall using PowerShell

By default Windows Firewall is turned on Windows Servers. Instead of turning off whole firewall you should allow only some ports go through. To do this using PowerShell you need only one simple line of code:

New-NetFirewallRule -DisplayName mssql -LocalPort 1433 -Protocol tcp

This example opens Microsoft SQL Server TCP port 1433 for incoming connections. Nice and easy line. Especially handy, when you need to do this using script on multiple servers.

To remove this rule, you should use the following command (mssql being the displayname of the rule):

Remove-NetFirewallRule -DisplayName mssql

11 August 2015

How to get your public IP in PowerShell

Ever wanted to know your public IP address programmatically in PowerShell? Here’s a good oneliner for you:

(Invoke-WebRequest http://myip.eu ).ParsedHtml.body.innerText.Split()[15]

It will get a sample page from myip.eu page, parse this html page body and find in text only version a space splitted part with serial number 15. No warranty though that this page work forever and the page result is formatted the same in future. Still worth a try.

02 February 2015

How to add domain user to local administrator group using PowerShell

All you need is following one-liner:

([ADSI]"WinNT://localhost/administrators,group").psbase.Invoke("Add",([ADSI]"WinNT://domain/user").path)

You need to change the domain/user to your actual domain name and user name (contoso/john for example).

05 January 2015

Get all sites and subnets in AD using PowerShell

I wondered if there is a command like Get-ADSite or Get-ADSubnet in PowerShell but it turns out there isn’t.

After surfing around the net I ended up writing this oneliner:


Get-ADObject -SearchB (Get-ADRootDSE).ConfigurationNamingContext -f { objectClass -eq "site" } -Properties * | ForEach-Object { ''; $_.Name; foreach ($s in $_.siteObjectBL) { $s } }


The output lists all sites separated by empty line. For each sites all subnets are listed.

10 October 2014

How to find duplicate MAC addresses in SCVMM 2012 R2

Sometimes, when you move virtual machine from one host to another you can run into duplicate MAC address problem. Of course you can have other scenarios for that situation to happen, for example two hyper-v hosts sharing the same MAC address range etc.

If you have searched for solutions on the internet, you won’t be happy with them. At least I wasn’t. Because I didn’t see the VM name in the results.

So I invested some time and came up with that PowerShell script:

cls
Import-Module virtualmachinemanager
"Working..."
$result = Get-VM | foreach {
foreach ($nic in $_.VirtualNetworkAdapters) {
    $obj = new-object psobject
    $obj | add-member noteproperty Host ($_.Name)
    $obj | add-member noteproperty Type ($nic.MACAddressType)
    $obj | add-member noteproperty MAC ($nic.MACAddress)
    $obj
    }
}
"Done"
$result | sort MAC | ConvertTo-Csv -Delimiter `t -NoTypeInformation | clip

This will get all VM-s, go through each of them and display each virtual network adapters MAC address with the server name. This script will place the results in clipboard for easy pasting and analyzing in Excel.

image

19 August 2014

How to change time zone from command line

Sometimes you have an installation from network server (Windows Deployment Services) and you find that time zone is not selected correctly. Or you just forgot to select the correct one when installing from optical media.

Since Windows Vista/2008 you can use tzutil.exe utility from command line to do time zone related things.

You can script to change the time zone change. For example if you have site based logon scripts and your site is in a single time zone, you can add it to site specific Group Policy Object (GPO).

First take a list of available time zones with the tzutil /l command:

image

My time zone is with name FLE Standard Time, so to change the time zone to this one, I use the command tzutil /s "FLE Standard Time"

image

To check the new time zone, use tzutil /g command:

image