Monday, February 2, 2015

Outlook for Android and iOS


A lot of sites are now reporting the insecurity of the application Outlook which appeared januari 29th in the Apple AppStore. (Warning – Microsofts Outlook app for iOS breaks your company security) and (Microsoft Wants to Improve Your Mobile Email Experience with the New Outlook for iOS and Android) This is the same application (some rebranding has been done) as the Accompli app which is now purchased by Microsoft.

What is the problem with this app?
It is a good app. It looks very need, but to do what is does it needs a little something from you and it will store this information on the servers in the cloud (Now at AWS but soon Microsoft Azure)
What is this information it needs?.... That is your Username and Password.
What does it do with this information? .... It starts downloading your entire mailbox, and caches this in the cloud.
Why is this a problem? .... For a private person not so much.... You probably share all the information on Facebook, twitter etc anyway, and don't have secrets in your mail which other instances / agencies are interested in.... But for companies this might be a large issue. They usually have something setup which is referred to as a company security policy. This policy mostly states the following items:

  • Device must have a pincode or password
  • Device must be encrypted
  • In case of lost the device must be wiped
  • etc.

All these things are not possible with the new App. From an App it is NOT possible to set device settings such as encryptions and passwords. A wipe is also not possible (In some cases the mailbox is reported to be removed)....


What to do now?
Firewall
Block the application from entering your network. If possible do this on your firewall with an User-Agent filter.
Filter for the following user agents:

  • Outlook-iOS-Android
  • Outlook for iOS and Android

Exchange (Exchange 2010 and Higher)
You can also add an rule on your Exchange server which will block access to the mail environment.
New-ActiveSyncDeviceAccessRule -Characteristic DeviceModel -QueryString "Outlook for iOS and Android" -AccessLevel Block
Block or Quarantine the Outlook for iOS and Android App in Exchange Server and Office 365

Future
Microsoft is busy with this application, updating and modifying it. So it is important to keep an eye on the changes which will occur in this application.
I do think that the application has a lot of potential and is a way to go, but first some issues have to be resolved. But for now "Hands Off"

Tuesday, January 20, 2015

Exchange services

Today I was at a client which had an issue with their Exchange environment. They were installing updates and one of the Exchange servers was giving trouble after that.
When I logged on to the server I noticed that all services were disabled, and since I am lazy I scripted the recovery for this ;-)

I though I shared it with you. Maybe there can be a check before if the service is running or not, or if it is really disabled.. But mostly this is a quick fix for your Exchange environment.

get-service "msexcha*" | Set-Service -StartupType automatic
get-service HostControllerService | Set-Service -StartupType automatic
get-service wsbexchange | Set-Service -StartupType automatic
get-service FMS | Set-Service -StartupType automatic
get-service W3SVC | Set-Service -StartupType automatic
get-service IISADMIN | Set-Service -StartupType automatic
get-service pla | set-service -startuptype automatic
get-service RemoteRegistry | set-service -startuptype automatic
get-service SearchExchangeTracing | Set-Service -StartupType automatic
get-service "MSExchangeImap4" | set-service -StartupType manual
get-service "MSExchangeImap4BE" | set-service -StartupType manual
get-service "MSExchangePop3" | set-service -StartupType manual
get-service "MSExchangePop3BE" | set-service -StartupType manual

get-service HostControllerService | start-service
get-service FMS | start-service
get-service "msexcha*" -StartupType automatic | start-service
get-service wsbexchange | start-service
get-service W3SVC | start-service
get-service WinRM | start-service
get-service pla | start-service
get-service RemoteRegistry | start-service
get-service IISADMIN | start-service
get-service SearchExchangeTracing  | start-service

Monday, August 11, 2014

How to operate a secure Synology system...

With the current hype around the outbreak of #SynoLocker, a ransomware virus which encrypts all your files and only allows decryption after paying a ransom fee ($400), it is nice to have your Synology protected as good as possible to minimize the attack vectors (ways people can compromise the security) to a minimum without loosing any end-user usability and ease.

In the different forums you find the following advices:
* Disable the default Admin Account
* Change the default ports on the services
* Use SSL
* Don't use 3rd party applications
* etc.

Below I will describe what is in my opinion a good way to protect your Synology for attacks. I will be using 3rd party applications from the SynoCommunity repository.
Starting point is an up to date Synology system and you are logged on as an Admin user (Admin or a different user with admin-rights)

Below are the links to a series of posts to secure your Synology:
1. Make sure your synology is up to date
2. Publish the applications through HAProxy
3. More to come..

Synology : Publish through HAProxy

This is the second article in a series to secure your Synology NAS.

HAProxy enables users to access programs on their NAS without opening additional ports in the firewall. Also because the applications are not accessible on the ports which they normally run on, and you need to know the exact url to use, it is hard to exploit the application if there is an bug in the software. (For instance SYNOLOCKER)
If you use the DDNS service of Synology you can use names in front of the DDNS name to connect to the services.
f.i. https://dsm.mydemonas.synology.me would redirect me to the admin interface of my NAS.

To achieve this we need to install an additional program HA-Proxy. This is available through the repository from Syno Community. The address for the repository is: http://packages.synocommunity.com

What this tutorial will assist you in is the following:
1. Add the repository
2. Prepare the NAS for the application
2.a Install a certificate
2.b enable SSH
3. Install the application and pre-requisite
3.a some problem fixing
4. conclusion.

I hope this will help you ;)



Add the repository
First open the package center:

















When in Package center select Installed and click the button Settings












Click on Add, and fill in the following information:
Name: Syno Community
Location: http://packages.synocommunity.com


On the left hand side click on community and then refresh.



A lot of packages will appear here.



Create a Certificate
Before we install HAProxy we first need to update the certificate and enable SSH.

Go to Control Panel


 Open Security


Click on the TAB Certificate


Click on Create Certificate

In this tutorial we create a self-signed certificate, if you have a valid certificate you can import it here,  or you can create a certificate request which you can send to a certificate authority.

Fill-in your information

At common name fill in the DNS name you want to use. The DDNS service from synology can provide you with a DNS name, you can add the local ip adres in de Subject Alternative Name field. Click Apply



Enable SSH
Since the custom configuration of HAProxy is only available through the command line we must enable SSH to connect to the NAS.

Open Control panel

Open Terminal en SNMP
 Select Enable SSH Service and click Apply

Installation of the Package

Now we can install haproxy. Since a requirement is Python 2.7 or higher we first install Python.
Open Package Center

 Select Community

Look for the package python and click install

Wait until the installation is finished

Look for the application HAProxy and click install

HAProxy uses an username and password to protect the status page. Enter those here.
Default is admin admin
Click Next

Make sure the checkbox is ticked to run the application, and click apply

With version 1.5-dev25-12 there is an problem in the configuration which doesn't allow the application to run. We can however fix it ourselves.

Download putty

Open the downloaded program file and connect to the IPAdres of your NAS over SSH
The username is always root
The password is your admin password

Change the current folder to "/volume1/@appstore/haproxy/var and open the file haproxy.cfg

Commands:
  cd /volume1/@appstore/haproxy/var/
  vi haproxy.cfg

When the file opens scroll down to the part backend gateone.
Add verify none to the server line. For this press the i
add the words to the line. press ESC
type :wq [ENTER]

Now the package will run when we start it.

Conclusion
HAProxy will natively run on the ports 5080 and 5443
We can change these ports in the configuration file or you can modify your firewall (router) to forward the request incoming on port 80 or 443 to the ports of haproxy. By default the applications are only available over the https (5443) port but you can copy those lines to the http (5080) port option. This makes it less secure!!





Synology : Make sure it is up to date and you are informed of updates.

My first in a series is the advice to make sure your system is always up to date. The press release of Synology states that the current versions of the software where NOT vulnerable for this virus. So first we make your system send you emails if there is an update for your Synology.

Click on the start button (Top Left corner) and open Control Panel










Open Notification












If you have information of sending emails through a SMTPServer (Mail Server) you can use the first tab (Email) to enter this information.

Be sure to test the configuration. 



















If you don't have access to an email server to send the emails you can choose to use the Synology notification email server. you find this on the tab "Push Service"
Fill in your emailaddress, click Apply, after a few seconds a new button appears. Click on this button "send verification mail", open your email box and click on the verification link in this email.
Email notifications will now be send. 


















In the "Advanced" tab you can select which notifications you want to receive. I have selected all notifications



In the left menu go to "Update & Restore", in the page click on the button "Update Settings" and make sure that the system is checking for New and All updates and that the checkbox is checked to check and download these updates.


















Next close all the open pages, and open the Package Center













When the Package Center opens click on the Settings button














Make sure both options are selected on the General Tab



















On the tab Auto Update you can choose to Auto Update the Synology Packages



















Now you will receive emails if there are updates available for your Synology System or applications.

Thursday, June 5, 2014

Apple OSX 10.10 Yosemite sluggish and unresponsive or snappy as expected??

Last week Apple presented Mac OSX 10.10 Code name Yosemite. Now with better integration with your phone and ipad.... Off course I have to try this so I installed iOS 8 on my Phone(s) and OSX 10.10 on my Mac.

And then the troubles began... Not on the phone but on my Mac. It was unresponsive, memory hogging and throughout terrible. I even considered reverting back to OSX 10.9 Mavericks.
But I am not a quitter so the search for a solution started...

There is a side note that there is a NDA on OSX 10.10 and therefor there is little found on the internet about it and the problems which are found..

When I started looking at the resource usage I couldn't find anything off other than that kernel_task was using a lot of memory, but other than that nothing wrong... But whenever I switch between applications the screen froze and a colourful skippybal came in place of my cursor.. Since I have a lot of tweaks installed, I instantly started blaming them, and cleaned them away from my system.. But it didn't solve anything...

Maybe it where the add-ins I am using such as dropbox and bitcasa.. so deleted those. Still no response from my system..
In the meantime a forum was started for Yosemite where people started sharing their problems. On that forum someone shared that he had an unresponsive system and no sound. I had sound, but still worth a look. (http://forums.macrumors.com/showthread.php?t=1740460) In this thread it was suggested to remove a driver from a third-party add-on.
I checked if I had the same driver on my system, but no such luck.

Off to more digging into this issue, but still no luck in finding something. resetting the SMC and PRAM both didn't help and all other suggestions found on the internet for versions since 10.5

At that time I started looking at all open processes and applications. All tweaks where already removed but legitimate application such as VMWare Fusion, Parallels and Microsoft where still on my machine. Only one application was still running and that was Parallels Access. I had never used it and had always thought it part of parallels itself.
So I searched for problems between Yosemite and Parallels Access. But couldn't find any. I did find a post that it is an agent which allows you to use your iPad to control the Mac (http://forums.macrumors.com/showpost.php?p=18300289&postcount=25) Since it is not something I use, and I was in a PenTesting class where we just learned not to have anything installed you are not using since that might get attacked, I decided to uninstall the agent. In the link in the post was a link to a knowledge base article from Parallels in how to remove it (http://kb.parallels.com/en/117142) in which they have a script (Parallels Access Uninstall script) to remove the software. Just sudo run the script from terminal and it is gone...

One reboot later my system was responsive, snappy and nice to work with again..

I am not going to share any details and screenshots just yet, but I like that I can answer SMS texts on my laptop now :)

Monday, February 4, 2013

When you logon to Facebook....


When you logon to facebook you get the question: "How is it going, Bas?"...
Today I felt like answering the question. Below my answer.
Dear Facebook,

Thank you for asking... I am currently recuperating from a very hectic weekend.

I started the final migration of a dutch company on friday. It was the end of 4 months preparation. But although we didn't invite Murphy, he decided to show up anyways...
For the past 4 months our migration efforts were brought back to 7 or 8 scripts running at scheduled intervals. Daily manual checks were done of the logfiles and runtimes and we were very confident that the migration would be a success.

And there was Murphy and his Law (The prick)
Everything that could go wrong went wrong. Scripts failed to complete due to offline databases, disabled users, and rebooting servers.... (Who forgot to include the support team to suspend the maintenance windows)
Nothing is more frustrating than working on fixing a script to adapt to the new situation, having found the solution and than some ass decides to reboot the server you are working on...

So friday I clocked a 14 hour workday (hours after 12 are on saturday) to have finally migrated everything.... As that was what we believed... I was glad to have taken an hour of to visit Tian Dao to be treated for my high blood pressure and that was very relaxing... Thanks for that...

Saturday morning after about 3 hours sleep I started to check the logfiles. And found that all the steps are completed successful. Ahhhh Weekend was the thought.. and queue Murphy..

In this company there are some strict naming rules for users.... Which are not followed of-course. So when you want to migrate Jan Jansen you look for j.jansen conform the naming standards... And migrate someone totally different since the logon name for jan was JanJ... And you wonder why you cannot find him...

So after another long day (again 14 hours on the clock) we check into bed... for a nights rest... And a good night rest it was..

Sunday, fun day... Yeah.. last day of migration.. In the input list we found that several users were not given an email forward address to the new mail. and since a script flawless processes what you input the mail for those users were not forwarded.. Works as designed, but not as desired... So the torubleshooting starts... and remigrating those accounts.. But I managed to make it a shorter day, and after sleeping in I only managed to clock 8 hours of after care this day..

After a handover to my colleague for the aftercare on monday I went to bed for a good nights rest....

And a good nights rest it was...

So to answer your question Facebook. I am doing alright. A bit tired but fulfilled with a job well done...

So and now back to work and finish these reports which are due..

Goodday,

Bas Steelooper

Friday, January 25, 2013

In the pocket: Core Solutions of MS Exchange Server 2013 Customer Preview

Today I saw that another IT pro passed his exam and I thought about the beta exams I did for Microsoft Exchange 2013...

So I took al little trip to https://www.register.prometric.com/CandidateHistory.asp and found out that I passed the "Core Solutions of MS Exchange Server 2013 Customer Preview" (071-341) exam... To bad that I failed the "Advanced Solutions of MS Exch Serv 2013 Customer Preview" (070-342) exam..

But with the lack of experience I was able to obtain since I couldn't install Exchange 2013 in my Exchange 2010 environment I think I did rather well with only reading about all there is on Technet and other Tech blogs...

I hope to find the time to install Exchange 2013 soon in my environment and update all the scripts to this version...

Monday, January 21, 2013

Exporting mailboxes to PST-files the easy way

When doing a cross domain migration it can be usefull to export the mailboxes to a PST file.

When doing this for a large amount of mailboxes it can be useful to use a script to automate this...

As I am lazy, I searched the internet for such a script, and found one from Steve Goodman which was close to what I wanted.. But as needy as I am, I needed more.

I modified, and added to the script which you find below. And is is as good as I am going to make it. It works like a charm (as I do say so myself)

Also made it so that if you are going to export a lot of mailboxes the target share and the source servers won't die on you you can set the maximum concurrent to a number your environment will survive.
The script will start the first batch, wait until completion, and than start the second batch.

When finished it will write some info to the report folder, and the logs for the completed and the failed requests...

Thanks go to Jeff Wouters which reviewed the script for me. And to his blog for the Add-Module function, which gave me a good idea for an add-SnapIN function which does basically the same but than for SnapIns.. so if you run the script multiple times you won't get an error :-)

# Exchange 2010 SP1 Mailbox Export Script
# Original script from : Steve Goodman (http://www.stevieg.org/2010/07/using-the-exchange-2010-sp1-mailbox-export-features-for-mass-exports-to-pst/)
# input from Jeff Wouters ( www.jeffwouters.nl)
# deviations from original script:
# - option to export all in the organisation
# - option to export all in a list
# - option to include archive mailboxes
# - option to exclude dumpster
# - option to set a maximum concurrent exports
# - no need to run from Exchange PowerShell. Needed library is loaded at runtime
$starttime = get-date -displayhint time
###############
# Settings    #
###############

# Pick ONE of the two below. If you choose both, it will use $Server.
$Server
$Database
$list = "\\server\share\users1.csv"

# Share to export mailboxes to. Needs R/W by Exchange Trusted Subsystem
# Must be a UNC path as this is run by the CAS MRS service.
$ExportShare = "\\server\share\pst\"
if (!(test-path -path $ExportShare -pathtype container))
{
 mkdir $ExportShare
}

# After each run a report of the exports can be dropped into the directory specified below. (The user that runs this script needs access to this share)
# Must be a UNC path or the full path of a local directory.
$ReportShare = "\\server\share\log\"
if (!(test-path -path $ReportShare -pathtype container))
{
 mkdir $ReportShare
}

# Shall we remove the PST file, if it exists beforehand? (The user that runs this script needs access to the $ExportShare share)
# Valid values: $true or $false
$RemovePSTBeforeExport = $true

# Do we want to include Archive Mailboxes
$IncludeArchive = $true

# Do we want to exclude dumpster
# currently not working as intended. workarround in place
$ExcludeDumpster = $false

# How many concurrent exports do we want?
# This must be an even number (2, 4, 6, 50, 100, 200, 1000 etc)
$maxConcurrentExports = 200

###############
# Code        #
###############

# function created by Jeff Wouters (www.jeffwouters.nl)
function Check-LoadedModule
{
  Param( [parameter(Mandatory = $true)][alias("Module")][string]$ModuleName)
  $LoadedModules = Get-Module | Select Name
  if (!$LoadedModules -like "*$ModuleName*") {Import-Module -Name $ModuleName}
}

# Deviation from Jeff Wouters function but for PSAddins
function Check-LoadedSnapIN
{
  Param( [parameter(Mandatory = $true)][alias("SnapIN")][string]$SnapINName)
 if ( (Get-PSSnapin -Name $SnapINName -ErrorAction SilentlyContinue) -eq $null )
 {
     Add-PsSnapin $SnapINName
 }
}

# If Archives are included we get 2 exports at a time. so we need to divide the maximum by 2
if ($includeArchive){
 $maxConcurrentExports = $maxConcurrentExports / 2
}

# load the Exchange powershell snapin if not loaded
Check-LoadedSnapIN Microsoft.Exchange.Management.PowerShell.E2010

# this function will create the MailboxExportRequests.
function exportMailbox ([String]$CurrentUser) {
     if ($RemovePSTBeforeExport -eq $true -and (Get-Item "$($ExportShare)\$($CurrentUser).PST" -ErrorAction SilentlyContinue))
     { 
         Remove-Item "$($ExportShare)\$CurrentUser.PST" -Confirm:$false -ErrorAction SilentlyContinue
         Remove-Item "$($ExportShare)\$CurrentUser-Archive.PST" -Confirm:$false -ErrorAction SilentlyContinue
     }
     if ($ExcludeDumpster){ # workarround if else. Would rather place this inline in the vode.
      New-MailboxExportRequest -BatchName $BatchName -Mailbox $CurrentUser -FilePath "$($ExportShare)\$CurrentUser.pst" -ExcludeDumpster
      if ($IncludeArchive){
       New-MailboxExportRequest -BatchName $BatchName -Mailbox $CurrentUser -FilePath "$($ExportShare)\$CurrentUser-Archive.pst" -IsArchive -ExcludeDumpster
      }
     } else {
      New-MailboxExportRequest -BatchName $BatchName -Mailbox $CurrentUser -FilePath "$($ExportShare)\$CurrentUser.pst"
      if ($IncludeArchive){
       New-MailboxExportRequest -BatchName $BatchName -Mailbox $CurrentUser -FilePath "$($ExportShare)\$CurrentUser-Archive.pst" -IsArchive
      }
  }     
}

# This function makes the script wait for completion of all exports.
function waitForCompletion {
 while ((Get-MailboxExportRequest -BatchName $BatchName | Where {$_.Status -eq "Queued" -or $_.Status -eq "InProgress"}))
 {
     clear
     Write-Output "Waiting for the exports to complete"
     Get-MailboxExportRequest -BatchName $BatchName | Get-MailboxExportRequestStatistics | Where {$_.Status -eq "Queued" -or $_.Status -eq "InProgress"} | Out-Default | Format-Table
     sleep 60
 }
}

# Make batch name
$date=Get-Date
$BatchName = "Export_$($date.Year)-$($date.Month)-$($date.Day)_$($date.Hour)-$($date.Minute)-$($date.Second)"

if ($ExcludeDumpster){
 $additionalParm = "-ExcludeDumpster $true"
} else {
 $additionalParm = ""
}

# the collection of what to be export
if ($Server)
{
 write-output "Using Server"
    if (!(Get-ExchangeServer $Server -ErrorAction SilentlyContinue))
    {
        throw "Exchange Server $Server not found";
    }
    if (!(Get-MailboxDatabase -Server $Server -ErrorAction SilentlyContinue))
    {
        throw "Exchange Server $Server does not have mailbox databases";
    }
    $Mailboxes = Get-Mailbox -Server $Server -ResultSize Unlimited
} elseif ($Database) {
 write-output "Using database" 
    if (!(Get-MailboxDatabase $Database -ErrorAction SilentlyContinue))
    {
        throw "Mailbox database $Database not found"
    }
    $Mailboxes = Get-Mailbox -Database $Database -ResultSize Unlimited
} elseif ($list) {
 write-output "Using list: $list"
 $userlist = Import-CSV $list
} else {
    write-output "None of the above, so exporting all mailboxes.."
    $mailboxes = Get-Mailbox -ResultSize Unlimited
} 

# The Export
if ($list){
 Write-Output "Queuing $($userlist.Count) mailboxes as batch '$($BatchName)'"
 $teller = 0
 # Queue all mailbox export requests
 foreach ($user in $userlist)
 {
     $teller = $teller + 1
     $curuser =  $user.SamAccountName
     exportMailbox $curuser
     if ($teller -gt $maxConcurrentExports){
  Write-Output "Waiting for batch to complete"
  # Wait for mailbox export requests to complete
  waitForCompletion 
  $teller = 0
     }
 }  
 # Wait for mailbox export requests to complete
 waitForCompletion
}elseif ((!$Mailboxes) -and (!$Mailboxes.Count)) {
    throw "No mailboxes found on $Server or single Mailbox."
} else {
 Write-Output "Queuing $($Mailboxes.Count) mailboxes as batch '$($BatchName)'"
 # Queue all mailbox export requests
 $teller = 0
 foreach ($Mailbox in $Mailboxes)
 {
     $teller = $teller + 1
     exportMailBox $Mailbox.alias
     if ($teller -gt $maxConcurrentExports){
  Write-Output "Waiting for batch to complete"
  # Wait for mailbox export requests to complete
  waitForCompletion 
  $teller = 0
     }
 }
 # Wait for mailbox export requests to complete
 waitForCompletion
}

# Write reports if required
if ($ReportShare)
{
    Write-Output "Writing reports to $($ReportShare)"
    $Completed = Get-MailboxExportRequest -BatchName $BatchName | Where {$_.Status -eq "Completed"} | Get-MailboxExportRequestStatistics | Format-List
    if ($Completed)
    {
        $Completed | Out-File -FilePath "$($ReportShare)\$($BatchName)_Completed.txt"
    }
    $Incomplete = Get-MailboxExportRequest -BatchName $BatchName | Where {$_.Status -ne "Completed"} | Get-MailboxExportRequestStatistics
    if ($Incomplete)
    {
        $Incomplete | Format-List | Out-File -FilePath "$($ReportShare)\$($BatchName)_Incomplete_Report.txt"

  if (!$list){
   $list = "$($ReportShare)\$($BatchName)_failedpst.csv"
  }
  set-content -Value "Failed-PST" -Path $list".new"
  foreach ($woops in $Incomplete) {
   add-content -Value $woops.FilePath -Path $list".new"
  }

    }
}

$endtime = get-date -displayhint time

$runtimefile = "$($ReportShare)\$($BatchName)_runtime.txt"
$runtimeentry0 = $starttime.tostring() + ' - ' + $endtime.tostring()
$runtimeentry1 = "Completed exports: " + $completed.count
$runtimeentry2 = "Failedexports: " + $Incomplete.count
$runtimeentry3 = "Errored users:"
$runtimeentry4 = ( get-content -Path $list".new" | out-string)
Set-Content -Value $runtimeentry0 -Path $runtimefile
add-content -Value $runtimeentry1 -Path $runtimefile
add-content -Value $runtimeentry2 -Path $runtimefile
add-content -Value $runtimeentry3 -Path $runtimefile
add-content -Value $runtimeentry4 -Path $runtimefile

# Remove Requests
Write-Output "Removing requests created as part of batch '$($BatchName)'"
Get-MailboxExportRequest -BatchName $BatchName | Remove-MailboxExportRequest -Confirm:$false

Get Directory permission with powershell

One of my customers was facing a migration of their data to a new location. It was a cross domain migration so we don't want to take all the permissions with us in the migration (robocopy /DATS) and needed to find out the current situation.

Before I used the tool Security Explorer from Little Wonders.. And found out that through several take overs this is now Dell... (Scriptlogic -> Quest --> Dell)

since the software had gotten richer over the years with additional functions the price had also gone up, and is now only available in a time limited license..

So I thought, I can do this myself in PowerShell... And the result was very good (as I do say so myself)

I started out with the following script to get the permissions on the first 3 levels..
$OutFile = "C:\temp\folder-Permissions.csv"
$Header = "Folder Path,IdentityReference,AccessControlType,FileSystemRights,IsInherited"
Del $OutFile
Add-Content -Value $Header -Path $OutFile 

$RootPath = "z:\"

$Folders = get-CHildItem $RootPath | where {$_.psiscontainer -eq $true}

foreach ($Folder in $Folders){
 $ACLs = get-acl $Folder.fullname | ForEach-Object { $_.Access  }
 Foreach ($ACL in $ACLs){
  if ($ACL.IdentityReference -eq "BUILTIN\Administrators"){
  }else{
   $OutInfo = $Folder.Fullname + ";" + $ACL.IdentityReference  + ";" + $ACL.AccessControlType + ";" + $ACL.FileSystemRights + ";" + $ACL.IsInherited
   Add-Content -Value $OutInfo -Path $OutFile
  } 
 }
}

$Folders = get-CHildItem $RootPath\* | where {$_.psiscontainer -eq $true}

foreach ($Folder in $Folders){
 $ACLs = get-acl $Folder.fullname | ForEach-Object { $_.Access  }
 Foreach ($ACL in $ACLs){
  if ($ACL.IdentityReference -eq "BUILTIN\Administrators"){
  }else{
   $OutInfo = $Folder.Fullname + ";" + $ACL.IdentityReference  + ";" + $ACL.AccessControlType + ";" + $ACL.FileSystemRights + ";" + $ACL.IsInherited
   Add-Content -Value $OutInfo -Path $OutFile
  } 
 }
}

$Folders = get-CHildItem $RootPath\*\* | where {$_.psiscontainer -eq $true}

foreach ($Folder in $Folders){
 $ACLs = get-acl $Folder.fullname | ForEach-Object { $_.Access  }
 Foreach ($ACL in $ACLs){
  if ($ACL.IdentityReference -eq "BUILTIN\Administrators"){
  }else{
   $OutInfo = $Folder.Fullname + ";" + $ACL.IdentityReference  + ";" + $ACL.AccessControlType + ";" + $ACL.FileSystemRights + ";" + $ACL.IsInherited
   Add-Content -Value $OutInfo -Path $OutFile
  } 
 }
}

$Folders = get-CHildItem $RootPath\*\*\* | where {$_.psiscontainer -eq $true}

foreach ($Folder in $Folders){
 $ACLs = get-acl $Folder.fullname | ForEach-Object { $_.Access  }
 Foreach ($ACL in $ACLs){
  if ($ACL.IdentityReference -eq "BUILTIN\Administrators"){
  }else{
   $OutInfo = $Folder.Fullname + ";" + $ACL.IdentityReference  + ";" + $ACL.AccessControlType + ";" + $ACL.FileSystemRights + ";" + $ACL.IsInherited
   Add-Content -Value $OutInfo -Path $OutFile
  } 
 }
}

So since this worked, I started optimizing the code for posting on my blog.. and came up with the following. (Remember I want only the first 3 levels)

$OutFile = "C:\temp\folder-Permissions.csv"
$Header = "Folder Path,IdentityReference,AccessControlType,FileSystemRights,IsInherited"
Del $OutFile
Add-Content -Value $Header -Path $OutFile 

$RootPath = "z:\"

Function getSubFolderpermissions ($folders){
 foreach ($Folder in $Folders){
  $ACLs = get-acl $Folder.fullname | ForEach-Object { $_.Access  }
  Foreach ($ACL in $ACLs){
   if ($ACL.IdentityReference -eq "BUILTIN\Administrators"){
   }else{
    $OutInfo = $Folder.Fullname + ";" + $ACL.IdentityReference  + ";" + $ACL.AccessControlType + ";" + $ACL.FileSystemRights + ";" + $ACL.IsInherited
    Add-Content -Value $OutInfo -Path $OutFile
   } 
  }
 }
}


$Folders = get-CHildItem $RootPath | where {$_.psiscontainer -eq $true}
getSubFolderpermissions $folders

$Folders = get-CHildItem $RootPath\* | where {$_.psiscontainer -eq $true}
getSubFolderpermissions $folders

$Folders = get-CHildItem $RootPath\*\* | where {$_.psiscontainer -eq $true}
getSubFolderpermissions $folders

$Folders = get-CHildItem $RootPath\*\*\* | where {$_.psiscontainer -eq $true}
getSubFolderpermissions $folders


but still I didn't like this..

so after I little active rewriting I found this:
$OutFile = "C:\temp\folder-Permissions.csv"
$Header = "Folder Path,IdentityReference,AccessControlType,FileSystemRights,IsInherited"
remove-item $OutFile
Add-Content -Value $Header -Path $OutFile 

$RootPath = "\\san2\hdswbr$\Docs"
$levelsdeep = 3

Function getSubFolderpermissions ($Folders, $currentlevel){
 if ($currentlevel -lt ($levelsdeep + 1)){
  foreach ($map in $Folders){
   $subfolders = get-CHildItem $map.fullname | where {$_.psiscontainer -eq $true}
   if (!($subfolders -eq $null)){
    getSubFolderPermissions $subfolders ($currentlevel +1)
   }
   $ACLs = get-acl $map.fullname | ForEach-Object { $_.Access  }
   Foreach ($ACL in $ACLs){
    if ($ACL.IdentityReference -eq "BUILTIN\Administrators"){
    }else{
     $OutInfo = $map.Fullname + ";" + $ACL.IdentityReference  + ";" + $ACL.AccessControlType + ";" + $ACL.FileSystemRights + ";" + $ACL.IsInherited
     Add-Content -Value $OutInfo -Path $OutFile
    } 
   }
  }
 }
}

$Mappen = get-CHildItem $RootPath | where {$_.psiscontainer -eq $true}
getSubFolderpermissions $Mappen, 0