Tag Archives: Convert

Filtering and Arraying 101 Powershell

So I try to teach my colleagues a bit more about Powershell from time to time. I have advised them a bit about how they can filter values to meet their requirements. Our architect wanted an export of all user accounts. When I simply exported all AD users in the domain he said that the amount of users is way too large. He asked me how this happend and where all those users are coming from? I wanted to give him an export of all enabled users in ActiveDirectory per OU. Actually I just wanted to show him the amount of users per OU. So I made a little script that does that job. However this is an excellent opportunity for someone to start working with Powershell. So I’ve written a little 101 about how they should start.

Step 1

Import the module ActiveDirectory.

IPMO ActiveDirectory

Step 2

You want to know in what OU a user is situated. Maybe the CMDlet Get-ADUser returns this value. By running the command Get-ADUser SAMACCOUNTNAME -Properties * you’ll get all the available properties. To display the methods and functions you can also use this command, in correspondence with the CMDlet Get-Member (Alias GM). You’ll have to run:

Get-ADUser SAMACCOUNTNAME -Properties * | GM

This prints all available methods,functions,properties and so forth. If you see a property, that is name something like, parent or OU you’ll be lucky. Unfortunately in Powershell 1,2 and 3 there isn’t such a property. So you have to find other ways to get the parent OU.

Step 3

Many CMDlets can be used against the registry, file systems, certificate stores or the Active Directory. In this case you’ll still have to know the containing OU. So probably the best way is to use the CanonicalName which contains this information. However that would kill all the fun. In this example DistinguishedName will have to do it. This obviously displays the containing OU. To save the DistinguishedName in a string run:

$Result = (Get-ADUser SAMACCOUNTNAME).DistinguishedName

Step 4

The DistinguishedName contains the CN of a user. You want to filter that out of the string. But how do you do that? Again use GM to see if you can convert the value to it’s parent or the get what is possible with the value.  To do so run the command:

$Result | GM

You can replace the CN as text. This can be really really tricky. To do so run the command in step 3 without the .DistinguishedName property behind it. Next run the command:

$Result.DistinguishedName.Replace(("CN="+$Result.Name+","),'')

There is no right or wrong if the result is the same and it meets your goals. That is an important lesson to learn.

Step 5

To select an item use the CMDlet Get-Item (Alias GI). This CMDlet will let you select any file, folder or object in the registry,file system, certificate store or AD. Actually you can use it against any mounted PSdrive. We still want to know the containing OU. So in this case we will look up the DistinguishedName in the AD. Again use GM to find out what is possible with the output. To do so run:

GI "AD:\$Result" | GM

Step 6

As you can see the property PSParentPath exists. Maybe this displays the required output? Run the command:

(GI AD:\$Result).PSParentPath

Step 7

That output is not how you want it to be. The type is displayed. To be as clean as possible you will have to replace that part of the line. You can use the Replace method like this:

(GI AD:\$Result).PSParentPath.Replace("Microsoft.ActiveDirectory.Management\ActiveDirectory:://RootDSE/",'')

Step 8

To come back to the objective, we’ll have to export all enabled users. There are two ways to accomplish this.

$List = Get-ADUser -Filter * | ? {$_.Enabled -eq $True}

Or

$List = Get-ADUser -Filter {Enabled -eq $True}

Which one is better? The correct answer would be none. The result is what counts. The best thing is running the command that you can remember or that works best for you. In terms of performance the second command would be better. Try this:

(Measure-Command -Expression {$list = Get-ADUser -Filter * | ?{$_.Enabled -eq $True}}).TotalSeconds

(Measure-Command -Expression {$list = Get-ADUser -Filter {Enabled -eq $true}}).TotalSeconds

Step 9

Next you can form a “script” to collect all DistinguishedNames and replace the unwanted text. To do so run:

Foreach ($item in $List){$Result = (GI AD:\$item).PSParentPath.Replace("Microsoft.ActiveDirectory.Management\ActiveDirectory:://RootDSE/",'')
AC -Value $Result -Path ".\Output.csv"}

Step 10

We have a list called Output.csv. The only thing we have to do now is to count the number of occurrences. This is not necessary the best way to do it. You can save this output in an array if you like.  Below there are examples of many different ways to solve this problem. Below is an example of the last bit of a script.

$List2 = GC ".\Output.csv"
$Uniquelist = $list2 | Sort -Unique
Foreach ($UniqueItem in $Uniquelist){
[int]$Count = 0
Foreach ($Item in $list2){If ($Item -eq $UniqueItem){$Count++}}
$Outinfo = "$UniqueItem" + ";" + "$Count"
AC -Value $outinfo -Path ".\Counted OUs.csv"
}

There are lots of ways to get to your destination. I have generated a number of scripts to do this task.

Script 1

IPMO ActiveDirectory
$list = Get-ADUser -Filter * | ? {$_.Enabled -eq $True}
Foreach ($item in $List){$Result = (GI AD:\$item).psparentPath.Replace("Microsoft.ActiveDirectory.Management\ActiveDirectory:://RootDSE/",'')
AC -Value $Result -Path ".\Output.csv"}
$List2 = GC ".\Output.csv"
$Uniquelist = $list2 | Sort -Unique
Foreach ($UniqueItem in $Uniquelist){
[int]$Count = 0
Foreach ($Item in $list2){If ($Item -eq $UniqueItem){$Count++}}
$Outinfo = "$UniqueItem" + ";" + "$Count"
AC -Value $outinfo -Path ".\Counted OUs.csv"
}

This script generated two output files. A part of statics values is replaced.

Script 2

IPMO ActiveDirectory
$list = Get-ADUser -Filter * | ? {$_.Enabled -eq $True}
Foreach ($item in $list){$Result = $item.distinguishedName.Replace(("CN="+$item.Name+","),'')
AC -Value $Result -Path ".\Output.csv"}
$List2 = GC ".\Output.csv"
$Uniquelist = $list2 | Sort -Unique
Foreach ($UniqueItem in $Uniquelist){
[int]$Count = 0
Foreach ($Item in $list2){If ($Item -eq $UniqueItem){$Count++}}
$Outinfo = "$UniqueItem" + ";" + "$Count"
AC -Value $outinfo -Path ".\Counted OUs.csv"
}

This script contains a replace of dynamic content. You have to be very careful using such a replace. We have CN’s with a value like Berg, Steven van den. That comma is precisely the problem. To display a comma in the DistinguishedName a break is inserted. So the actual value is CN=Berg\, Steven van den,. Based on the specified condition this does not apply. Meaning that you will have inconsistent results. In script 3 this is corrected.

Script 3

IPMO ActiveDirectory
$list = Get-ADUser -Filter {Enabled -eq $True}
$List2 = @()
Foreach ($item in $list){$Result = $item.distinguishedName.Replace('\','').Replace(("CN="+$item.Name+","),'')
$List2 += $Result}
$Uniquelist = $list2 | Sort -Unique
Foreach ($UniqueItem in $Uniquelist){
[int]$Count = 0
Foreach ($Item in $list2){If ($Item -eq $UniqueItem){$Count++}}
$Outinfo = "$UniqueItem" + ";" + "$Count"
AC -Value $outinfo -Path ".\Counted OUs.csv"
}

Here the conditions are met. I have also included an empty array at the line 3. Next all values are added to that array. So only the correct file is exported. Be aware that is you do a double ” after the replace of the special character you’ll need a double backslash. In this case something like .Replace(“\\”,””). The backslash means a break stating a special character.

Even though this script delivers the correct output, I would still advise you to refrain from replacing dynamic content unless you are really sure that every condition is met and that you not filter out too much.

Script 4

IPMO ActiveDirectory
$list = (Get-ADUser -Filter {Enabled -eq $True}).DistinguishedName | %{(GI "AD:\$_").PSParentPath.Replace("Microsoft.ActiveDirectory.Management\ActiveDirectory:://RootDSE/",'')}
$Uniquelist = $list | Sort -Unique
Foreach ($UniqueItem in $Uniquelist){
[int]$Count = 0
Foreach ($Item in $list2){If ($Item -eq $UniqueItem){$Count++}}
$Outinfo = "$UniqueItem" + ";" + "$Count"
AC -Value $outinfo -Path ".\Counted OUs.csv"
}

Script 1 uses the CMDlet Get-Item (Alias GI) to collect the parent OU. In script 1 this is done in separate commands. You can combine this in one line let the example above. I have done this by using the CMDlet Foreach-Object (Alias %).

Script 5

IPMO ActiveDirectory
$list = (Get-ADUser -Filter {Enabled -eq $True}).DistinguishedName | %{(GI "AD:\$_").PSParentPath.Replace("Microsoft.ActiveDirectory.Management\ActiveDirectory:://RootDSE/",'')}
Foreach ($UniqueItem in ($List | Sort -Unique)){
[int]$Count = 0
Foreach ($Item in $list){If ($Item -eq $UniqueItem){$Count++}}
$Outinfo = "$UniqueItem" + ";" + "$Count"
AC -Value $outinfo -Path ".\Counted OUs.csv"
}

Unlike script 4 in shorted the script even further by not generation a separate unique item list.

Script 6

IPMO ActiveDirectory
$list = (Get-ADUser -Filter {Enabled -eq $True}).DistinguishedName | %{(GI "AD:\$_").PSParentPath.Replace("Microsoft.ActiveDirectory.Management\ActiveDirectory:://RootDSE/",'')}
Foreach ($UniqueItem in ($List | Sort -Unique)){
[int]$Count = 0
Foreach ($Item in $list){If ($Item -eq $UniqueItem){$Count++}}
AC -Value ("$UniqueItem" + ";" + "$Count") -Path ".\Counted OUs.csv"
}

The output string is combined in one line.

Script 7

IPMO ActiveDirectory
Get-ADUser -Filter {Enabled -eq $True} | % {($_).distinguishedName.Replace('\','').Replace(("CN="+$_.Name+","),'')} | Group | Select Name,Count | epcsv ".\Counted OUs.csv" -Delimiter ";" -NoTypeInformation

This example is even prettier. Nearly a oneliner. To count we use the Group-Object (Alias Group) te count the number of occurrences. Next we Select the fields we want. Followed by exporting the data by Export-CSV (Alias epcsv). This can be done with that other command aswel.

Script 8

IPMO ActiveDirectory
(Get-ADUser -Filter {Enabled -eq $True}).DistinguishedName | %{(GI "AD:\$_").PSParentPath.Replace("Microsoft.ActiveDirectory.Management\ActiveDirectory:://RootDSE/",'')} | Group | Select Name,Count | epcsv ".\Counted OUs.csv" -Delimiter ";" -NoTypeInformation

In this case you have few ways to select the data. Like these:

IPMO ActiveDirectory
Get-ADUser -Filter {Enabled -eq $True} | %{(GI AD:\$_).PSParentPath.Replace("Microsoft.ActiveDirectory.Management\ActiveDirectory:://RootDSE/",'')} | Group | Select Name,Count | epcsv ".\Counted OUs.csv" -Delimiter ";" -NoTypeInformation

Or

IPMO ActiveDirectory
Get-ADUser -Filter {Enabled -eq $True} | %{(GI AD:\$_).PSParentPath.Replace("Microsoft.ActiveDirectory.Management\ActiveDirectory:://RootDSE/",'')} | Group |  % { AC -Value ("$($_.Name)" + ";" + "$($_.Count)") -Path ".\Counted OUs.csv"}

Or

IPMO ActiveDirectory
Get-ADUser -Filter {Enabled -eq $True} | %{(GI AD:\$_).PSParentPath.Replace("Microsoft.ActiveDirectory.Management\ActiveDirectory:://RootDSE/",'')} | Group  | % { AC -Value ($($_.Name) + ";" +  ($($_).Group.Count)) -Path ".\Counted OUs.csv"}

Except one, these scripts all generate the same output. Know that there are many more ways to get the same output. Again the best method is the one you can remember and you feel comfortable using. If you like oneliners you’ll prefer script 8. If you like to have an overview of what is happening you’ll prefer script 1. Based on your skills in scripting/Powershell you’ll choose anything in between.

You could also have selected CanonicalName. This would have been a lot easier as it doesn’t contain any breaking (\). Another advantage would be that you can sort alphabetically. Since DistinguishedName is formed from the deepest to the highest level is it only possible to sort based on the last OU. Normally you would want to have this export correspond with the hierarchy of Active Directory. This is only possible with CanonicalName. CanonicalName is built up from highest in the hierarchy to the lowest container.

Reference table

Alias CMDlet
IPMO  Import-Module
 GM  Get-Member
 GI  Get-Item
 ?  Where-Object
AC  Add-Content
 GC  Get-Content
 Sort Sort-Object
 % Foreach-Object
 Group  Group-Object
 Select  Select-Object
epcsv  Export-CSV

I hope you’ve had fun!

Test whether PS Remoting is enabled

PSRemoting is a powerful way to manage remote computers. I often use this. However on some server PSRemoting is not enabled. A custom function can help you. When you import this in a Powershell session you can manage the server that don’t have PSRemoting enabled. I assume that you only have Windows Server 2008 and above servers in you domain.

First import the module or copy-paste it in you shell.

function Test-PSRemoting 
{ 
    param( 
        [Parameter(Mandatory = $true)] 
        $RemoteComputer 
    ) 
    
    try 
    {
		#Returns value 1 in a scriptblock on the remote computer
        $errorActionPreference = "Stop" 
        $result = Invoke-Command -ComputerName $RemoteComputer {1} 
    } 
    catch 
    { 
        Write-Verbose $_ 
        return $false 
    } 
     
    if($result -ne "1") 
    { 
        Write-Verbose "The remote computer: $RemoteComputer did not return the expected result. Please make sure you have enough privileges to connect to the computer." -f Red
        return $false 
    } 
    
    $true    
}

TestPSRemoting

Then to use it you can use the following code:

Import-Module ActiveDirectory
Import-Module ".\TestPSRemoting.psm1" -Force
$Servers = Get-ADComputer -Filter * -Properties OperatingSystem | Where {$_.OperatingSystem -match "Server"}
Write-host "There are " $Servers.count " servers found"
$DomainUser = ($env:userdomain+"\"+$env:username)
$secureString = Read-Host -AsSecureString "Enter your password"


Foreach ($Server in $Servers){
$Result = $null
$ServerName = $Server.Name
$Result = Test-PSRemoting $Server
If ($Result -eq $False){
Write-Host "PSRemoting will be enabled on server: $Server"
$Date = (Get-Date).AddMinutes(30)
schtasks /create /S $ServerName /RU $DomainUser /RP $secureString /SC Once /SD $date.ToString('dd"/"MM"/"yyy') /ST $date.ToString('HH":"mm') /TN "Enable PSRemoting" /TR "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe Enable-PSRemoting -Force" /F
}}

You need to be an Administrator of course or at least have enough permission to enable psremoting. If PSremoting is disabled an task will be scheduled to enable it within 30 minutes. You can enable PSRemoting remotely using the script. If you want to enable PSremoting on all workstations you’ll need to change the definition to something else. For example use a part of the DestinguishedName if an OU is called Workstations for example.

Good luck!

Script to check when a XenApp server is set to prohibit logons

It is hard to find out who set a server to Prohibit logons in XenApp. I had some spare time to make a oneliner for the service desk to search the eventlog for any records matching the specifics. The Logon process is run by the ImaService. When you know when to server is set to prohibit logon, you may find the administrator.

$List2 =@() ;$load = (qfarm /load) ;write-host $Load[1];Write-Host $load[2]; Foreach ($item in $load){If ($Item -match "ProhibitLogons"){Write-host $item;$Item2 = $item -split " " ;$item2 = $item2[0] ; $List2 += $Item2}} ;$Date = (Get-Date).AddDays(-1) ; Foreach ($item in $list2){Get-EventLog -LogName Application -after $Date -ComputerName $item -InstanceId 1073751835 | ? {$_.Message -match "Prohibit"} | Select TimeGenerated,MachineName}

Or if you feel more comfortable having a script you can do the following:

$List2 =@() 
$load = (qfarm /load) 
write-host $Load[1]
Write-Host $load[2]
Foreach ($item in $load){If ($Item -match "ProhibitLogons"){
Write-host $item
$Item2 = $item -split " " 
$item2 = $item2[0] 
$List2 += $Item2}} 
$Date = (Get-Date).AddDays(-1) 
Foreach ($item in $list2){
Get-EventLog -LogName Application -after $Date -ComputerName $item -InstanceId 1073751835 | ? {$_.Message -match "Prohibit"} | Select TimeGenerated,MachineName}

This “Script” runs a qfarm /load. Next presenting the users with a table from qfarm. It only lists server that are set to prohibitlogons. It splits the name from the rest and adds that to a array. The date is queried minus one day. You can change that to more or less. Next the Eventlog of the XenApp server is queried for a matching record. You can also set $_.EventID -match “10011” for the matching eventID. At the last step there’s a select-object for the TimeGenerated and MachineName

Renaming files and moving it to a different location

An OCE printer can only scan files to a FTP location with one name. There are no unique attributes that the Multifuctional printer can add to a file. This results in files being overwritten if not renamed immediately after being transferred. I’ve written a little script that is run every 5 seconds via Task Scheduler. This script renames files in a  unique format and then moves the file to some place else.

$Folder = "C:\Inetpub\FTProot\"
$Destination = "\\Ergensopdebozewereld"
$Applytime = (Get-Date).AddSeconds(-20)
$Content = @(gci $Folder | where {$_.LastWriteTime -lt $Applytime -and $_.PSIsContainer -eq $False})
Foreach ($item in $Content){$TEMP = $Item.LastWriteTime
$Time = Get-Date $TEMP -Format yyyyMMdd_HHmmss
$Name = $item.name.replace(".tif","")
Rename-Item -Path $Item.fullname -NewName "$Name_$Time.tif"
$Item = GI "$Folder\$Name_$Time.tif"
Move-Item -Path $Item -Destination $Destination -Force}

Convert String to Scriptblock Function

You cannot invoke-command a string. You should use a Scriptblock. If you import a value as a string you can convert it only if it is a single value string using the following command:

[scriptblock]::Create("$string")

To convert an multivalue array to scriptblock you can use a module as shown below:

function Convert-StringToScriptBlock {
param(
[parameter(ValueFromPipeline=$true,Position=0)]
[string]
$string
)
$sb = [scriptblock]::Create($string)
return $sb
}

Export-ModuleMember -Function 'Convert-StringToScriptBlock'

ZIP:

Convert-StringtoScripblock

Very basic hiding of words

Imagine a case where some user should fire up a script. You can specify credentials in plain text. However in some cases you shouldn’t want this. You can shuffle letters a bit so that an user cannot see the plain text password. You shouldn’t use this for anything higer than a low profile user account. Let’s say this is a test case.

Shuffle letters from CHAR To BYTE:

$Data = "Welkom01"
$Data=[CHAR[]]$data
$Pass = @()
Foreach ($letter in $Data){
$Pass += ([BYTE][CHAR]"$letter") 
}
write-host $pass -Separator " " -NoNewline

This will output 87 101 108 107 111 109 48 49

Shuffle letters from BYTE To CHAR:

$Data = "87 101 108 107 111 109 48 49"
$Data = $Data.Split(" ")
$Pass = @()
Foreach ($Item in $data) {$Pass += ([CHAR][BYTE]"$Item")}

$pass -join""

 

 

 

 

IP-address converter

In een Synology kan men IP-adressen blokkeren op basis van een lijst. Deze lijst moet alleen ip-adressen bevatten. Er kunnen geen subnets of iets dergelijk opgegeven worden. Met een Powershell script zijn deze ip-adressen om te zetten. Ga voor een lijst naar deze site. Selecteer een land, bijvoorbeeld China. Selecteer de Netmask variant en gooi deze in een CSV. Importeer vervolgens de Output in de automatisch blokkeren lijst. Dit gaat via het configuratie scherm –> Beveiliging –> Automatisch blokkeren –> Blokkeren –> Importeer lijst

 

PS1:

<#
.SYNOPSIS
Imports function for Get-IPrange. Imports CSV. Export List of IP-addresses. Expect XML file with content. Expects CSV file with Subnets

.NOTES
File Name : IPrangeconverter.ps1
Author    : Steven van den Berg (Bexit)
Date      : 9:00 Vrijdag 14 januari 2014
Requires  : PowerShell v3.0
Tag       : PowerShell, Get-IPrange

#>

#Function
function Get-IPrange 
{ 
<#  
  .SYNOPSIS   
    Get the IP addresses in a range  
  .EXAMPLE  
   Get-IPrange -start 192.168.8.2 -end 192.168.8.20  
  .EXAMPLE  
   Get-IPrange -ip 192.168.8.2 -mask 255.255.255.0  
  .EXAMPLE  
   Get-IPrange -ip 192.168.8.3 -cidr 24  
#>  

param  
(  
  [string]$start,  
  [string]$end,  
  [string]$ip,  
  [string]$mask,  
  [int]$cidr  
)  

function IP-toINT64 () {  
  param ($ip)  

  $octets = $ip.split(".")  
  return [int64]([int64]$octets[0]*16777216 +[int64]$octets[1]*65536 +[int64]$octets[2]*256 +[int64]$octets[3])  
}  

function INT64-toIP() {  
  param ([int64]$int)  

  return (([math]::truncate($int/16777216)).tostring()+"."+([math]::truncate(($int%16777216)/65536)).tostring()+"."+([math]::truncate(($int%65536)/256)).tostring()+"."+([math]::truncate($int%256)).tostring() ) 
}  

if ($ip) {$ipaddr = [Net.IPAddress]::Parse($ip)}  
if ($cidr) {$maskaddr = [Net.IPAddress]::Parse((INT64-toIP -int ([convert]::ToInt64(("1"*$cidr+"0"*(32-$cidr)),2)))) }  
if ($mask) {$maskaddr = [Net.IPAddress]::Parse($mask)}  
if ($ip) {$networkaddr = new-object net.ipaddress ($maskaddr.address -band $ipaddr.address)}  
if ($ip) {$broadcastaddr = new-object net.ipaddress (([system.net.ipaddress]::parse("255.255.255.255").address -bxor $maskaddr.address -bor $networkaddr.address))}  

if ($ip) {  
  $startaddr = IP-toINT64 -ip $networkaddr.ipaddresstostring  
  $endaddr = IP-toINT64 -ip $broadcastaddr.ipaddresstostring  
} else {  
  $startaddr = IP-toINT64 -ip $start  
  $endaddr = IP-toINT64 -ip $end  
}  

for ($i = $startaddr; $i -le $endaddr; $i++)  
{  
  INT64-toIP -int $i  
} 

}

#XML
Clear
#Import XML Config File
$xmlConfigfile = ".IPAddressConverter.xml"

	While (((Test-Path $xmlConfigfile) -eq $false) -or ($NoXML)){
		[System.Windows.Forms.MessageBox]::Show("ERROR: $xmlConfigfile not found!")
	write-host De XML file kan niet gevonden worden -F Red
	If (!($psISE)){"Press any key to continue...";[void][System.Console]::ReadKey($true)}
	exit
	}
If (-not ($CSV -and $Outfile)) {
		$xml = get-content $xmlConfigfile
		If (-not $CSV) {$CSV = $xml.Config.Settings.CSV}
		If (-not $Header) {$Header = $xml.Config.Settings.Header}
		If (-not $Outfile) {$Outfile = $xml.Config.Settings.Outfile}
		}

# The method of reading a .CSV file below ensures that a single line csv is also handled correct
	While (((Test-Path $CSV) -eq $false) -or ($NoCSV)){
		[System.Windows.Forms.MessageBox]::Show("ERROR: $xmlConfigfile not found!")
	write-host De CSV file kan niet gevonden worden -F Red
	If (!($psISE)){"Press any key to continue...";[void][System.Console]::ReadKey($true)}
	exit
	}

$list = @(import-csv -Delimiter '/' $CSV)
write-host ".CSV file contains" $list.count " lines." -F Yellow -B DarkCyan
$list[0]

if ($error.count -ne 0)

{
	write-host "An error occurred during the operation. Details follow:"
	$error[0].categoryInfo
	$error[0].invocationinfo
	write-host "=========================================================="
	write-host "Quit due to an error" -Fore Red
	Exit
}
else
{
	#"Successfully opened .CSV file..."
}

#Loop through .CSV file
foreach($entry in $list)

{
	# Reset the variable to make sure that they are clean before processing a user.
	$IP=$entry.IP
	$Mask=$entry.Mask

$list = Get-IPrange -ip $IP -mask $Mask
Add-Content -Value $list -Path $OutFile
}

XML:

<Config> 
  <Settings>
	<CSV>.IPAddressConverter.csv</CSV>
	<Outfile>.Output.csv</Outfile>
  </Settings>
</Config>

CSV:

IP/MASK
1.1.1.1/255.255.255.0

 

Functie (Optioneel):

function Get-IPrange 
{ 
<#  
  .SYNOPSIS   
    Get the IP addresses in a range  
  .EXAMPLE  
   Get-IPrange -start 192.168.8.2 -end 192.168.8.20  
  .EXAMPLE  
   Get-IPrange -ip 192.168.8.2 -mask 255.255.255.0  
  .EXAMPLE  
   Get-IPrange -ip 192.168.8.3 -cidr 24  
#>  

param  
(  
  [string]$start,  
  [string]$end,  
  [string]$ip,  
  [string]$mask,  
  [int]$cidr  
)  

function IP-toINT64 () {  
  param ($ip)  

  $octets = $ip.split(".")  
  return [int64]([int64]$octets[0]*16777216 +[int64]$octets[1]*65536 +[int64]$octets[2]*256 +[int64]$octets[3])  
}  

function INT64-toIP() {  
  param ([int64]$int)  

  return (([math]::truncate($int/16777216)).tostring()+"."+([math]::truncate(($int%16777216)/65536)).tostring()+"."+([math]::truncate(($int%65536)/256)).tostring()+"."+([math]::truncate($int%256)).tostring() ) 
}  

if ($ip) {$ipaddr = [Net.IPAddress]::Parse($ip)}  
if ($cidr) {$maskaddr = [Net.IPAddress]::Parse((INT64-toIP -int ([convert]::ToInt64(("1"*$cidr+"0"*(32-$cidr)),2)))) }  
if ($mask) {$maskaddr = [Net.IPAddress]::Parse($mask)}  
if ($ip) {$networkaddr = new-object net.ipaddress ($maskaddr.address -band $ipaddr.address)}  
if ($ip) {$broadcastaddr = new-object net.ipaddress (([system.net.ipaddress]::parse("255.255.255.255").address -bxor $maskaddr.address -bor $networkaddr.address))}  

if ($ip) {  
  $startaddr = IP-toINT64 -ip $networkaddr.ipaddresstostring  
  $endaddr = IP-toINT64 -ip $broadcastaddr.ipaddresstostring  
} else {  
  $startaddr = IP-toINT64 -ip $start  
  $endaddr = IP-toINT64 -ip $end  
}  

for ($i = $startaddr; $i -le $endaddr; $i++)  
{  
  INT64-toIP -int $i  
} 

}

ZIP:

IPAddressConverter