Scripting tips – Point to the dir from which the script was run.

Standard

When working with Powershell you often need to interact with other files when executing your script. Dealing with input files, output files and temp files are usually integral parts of script writing. When working with files you usually need to specify the absolute path to each file. However this makes the script less “robust” as you will need to change these paths if you also change the location of the script by copying it or moving it. This means extra work as you will need to modify the script every time you move it or copy it. Furthermore if you intend on giving the script for someone else to run they might complain that it’s not working because they haven’t got the paths right.

– Creating an object which always points to the script dir.

I have already used the following lines of code in many of my scripts but I find them so useful I thought they deserved their own post.

$scriptpath = $MyInvocation.MyCommand.Path
$dir = Split-Path $scriptpath

The whole thing is as simple as writing the above two lines of code. They will create the object $dir which always point to the path from where this script was run.

– How do I use this when referring to files in my scripts?

Now, when you wish to add a file to your script you can do it like the examples shown below.

$inputFile = "$dir\input.txt"

$outputFile = "$dir\output.txt"
New-Item -ItemType File $outputFile -Force

$logFile = "$dir\logs\logfile.txt"
New-Item -ItemType File $logFile -Force

$inputFile now points to a file called “input.txt” located in your script directory.

The $dir object is also useful when creating new files to make sure they are created in the correct locations. For instance $outputFile is a path that points to a file “output.txt” in the script directory. If it doesn’t exist yet you can then create the file with this line: New-Item -ItemType File $outputFile -Force.

Also, if you for instance want to add logging functionality to your script you can create the log file in a new dir in your script directory called “logs” by using the last example:
$logFile = “$dir\logs\logfile.txt”
New-Item -ItemType File $logFile -Force

– Benefits of using file paths like this

As you can see using the $dir object also allows you to easily maintain a directory structure for your files which will always remain the same no matter where you move the script. If you now create a script and refer to your files/directories like above and give it to a friend/colleague, it will always work no matter where he runs it from and any script output files will be created in the script directory. This will make the script much easier for others to use and save you a lot of trouble.

– Finding the correct scope when using MyInvocation.MyCommand.Path

In most cases creating the $dir object like above will work perfectly without any problems. However in some cases you will need to work a little with the scope of the variable in order to make it work. For instance if you are using it in a child job or from a .NET form you are running you might need to change the code to look like this:

$scriptPath = $script:MyInvocation.MyCommand.Path
$dir = Split-Path $scriptpath

If you run into any trouble you can change to code to look like above which should solve the problems.
You can read more about scopes in powershell here:
http://technet.microsoft.com/en-us/library/hh847849.aspx

– That’s it!

I hope this post will be helpful to you and let you easily work with paths and files in your scripts.

Advertisements

Powershell – Get DNS A records and export to CSV

Standard

When managing and cleaning up your IP addresses/ranges it can be very useful to get some lists of the records you have in your DNS zones. Here’s a simple script which gets the IP addresses/hostnames of the given DNS zones and exports the results to CSV.
The script is split into two parts Variables and script main. I will walk through and explain both parts below.

Variables

#VARIABLES
$scriptpath = $MyInvocation.MyCommand.Path
$dir = Split-Path $scriptpath
$CSV = "$dir\DNS_A_records.csv"
#parameters
$DNSServer = "Some_DNS_server"
$Zone1 = "myzone.local"
$Zone2 = "me.myzone.local"

I use the $dir object in the paths of my scripts as this object always points to the directory which the script has been run from. This is practical as it allows you to move/copy the script around without having to change any paths. $CSV is the path to the CSV file which will be created at the end of the script run.
Remember to fill out the parameters section before you run the script! $DNSServer is the name of your DNS server. $Zone1, $Zone2… etc are the names of the DNS zones which you want to get A records from. If you have more than 2 zones to get A records from then just add more objects to match the number of zones you need and add the zone names.

Script Main

#SCRIPT MAIN
clear
$DNS_Zones = @()
$DNS_Zones += $Zone1
$DNS_Zones += $Zone2
$hosts = @()
$DNS_Zones | % {
	$zone = $_
	Write-Host "Getting DNS A records from $zone"	
	$DNS_A_records = @(Get-WmiObject -Class MicrosoftDNS_AType -NameSpace Root\MicrosoftDNS -ComputerName $DNSServer -Filter "ContainerName = `'$zone`'")
	$DNS_A_records | % {
		$hostA = "" | select "hostname","IPAddress"
		$hostA.hostname = $_.OwnerName
		$hostA.IPAddress = $_.IPAddress
		$hosts += $hostA
	}
}
$hosts = $hosts | Sort-Object @{Expression={[Version]$_.IPAddress}}
$hosts | Export-Csv $CSV -NoTypeInformation -Force

In the script main I first create the array $DNS_Zones which will hold the different zone names. Then the zone names ($Zone1, $Zone2… etc.) are added to the array. If you created more than two zone objects in the variables section you must add them here too.
I now create the $hosts array which will hold the records we will wish export later. The next thing that happens is that we loop through the $DNS_Zones array. For each DNS Zone we get all A records using WMI and for each of these, a custom object with the properties hostname and IPAddress is created and added to the $hosts array.
I then sort the $hosts array by IP Address using the following code:
$hosts | Sort-Object @{Expression={[Version]$_.IPAddress}}
The @{Expression} argument allows you to add the [version] type declaration on the IPAddress property on the array elements/objects which in turn enables you to easily sort the IPs.
Finally the $hosts array is exported to CSV using the great Export-CSV powershell cmdlet.
I have copied in the full script below.I hope you find it useful. Enjoy!

################################################################################################
##Script:			Get-DNS_A_Records.ps1
##
##Description:		Gets all DNS A records from a given DNS server and exports the information 
#+					to a CSV file.
##Created by:		Noam Wajnman
##Creation Date:	April 07, 2014
################################################################################################
#VARIABLES
$scriptpath = $MyInvocation.MyCommand.Path
$dir = Split-Path $scriptpath
$CSV = "$dir\DNS_A_records.csv"
#parameters
$DNSServer = "Some_DNS_server"
$Zone1 = "myzone.local"
$Zone2 = "me.myzone.local"
#SCRIPT MAIN
clear
$DNS_Zones = @()
$DNS_Zones += $Zone1
$DNS_Zones += $Zone2
$hosts = @()
$DNS_Zones | % {
	$zone = $_
	Write-Host "Getting DNS A records from $zone"	
	$DNS_A_records = @(Get-WmiObject -Class MicrosoftDNS_AType -NameSpace Root\MicrosoftDNS -ComputerName $DNSServer -Filter "ContainerName = `'$zone`'")
	$DNS_A_records | % {
		$hostA = "" | select "hostname","IPAddress"
		$hostA.hostname = $_.OwnerName
		$hostA.IPAddress = $_.IPAddress
		$hosts += $hostA
	}
}
$hosts = $hosts | Sort-Object @{Expression={[Version]$_.IPAddress}}
$hosts | Export-Csv $CSV -NoTypeInformation -Force