Freitag, 7. Oktober 2016

SIDs and account names - a handy function for this

A handy function to get account names from SIDs and SIDs from account name, receiving local SIDs from remote machine will follow.

function Get-SID_NAME(
    [Parameter(Position=2)][string]$domain=$env:userdomain,
    [Parameter(Mandatory=$True,Position=1)][string]$search,
    [switch]$Local)
{
 if($search -match '\\'){
    $domain=$search.Split('\')[0]
    $search=$search.Split('\')[1]
    }
 if($search -match '^S-1-5-21-'){
    $objSID = New-Object System.Security.Principal.SecurityIdentifier($search)
    $objUser = $objSID.Translate( [System.Security.Principal.NTAccount])
    return $objUser.Value
    }else{
        if($Local){
            $objUser = New-Object System.Security.Principal.NTAccount($search)
            $strSID = $objUser.Translate([System.Security.Principal.SecurityIdentifier])
            return $strSID.Value
        } else {
            $objUser = New-Object System.Security.Principal.NTAccount($domain, $search)
            $strSID = $objUser.Translate([System.Security.Principal.SecurityIdentifier])
            return $strSID.Value
        }
    }
}


Source from most of the code :

https://technet.microsoft.com/en-us/library/ff730940.aspx

Mittwoch, 1. Juni 2016

Powershell reporting and fixing up IPv4 Subnet masks in a Windows Enviroment

Here have some Powershell for fixing up a "wrong" static set Subnetmask, like you have after resizing a Subnet - or got the wrong mask reported from the network guys.

So you heard about some wrong set up Subnets, uups this can happen. So first i would like to report all my windows servers in my ActiveDirectory and their setup Subnet mask on the IP address which is in DNS. Observing the report before fixing maybe nice, thatswhy DO NOT just copy&paste this code in one Script and run, maybe put it in ISE and run just selected code.

#How to Report 

Import-Module ActiveDirectory

$reportfilename = c:\Report-SRVs_SubNets.csv

Function Get-DnsEntry($iphost)
{
 If($ipHost -match "^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$")
  {
    [System.Net.Dns]::GetHostEntry($iphost).HostName
  }
 ElseIf( $ipHost )#-match "^.*\.\.*")
   {
    [System.Net.Dns]::GetHostEntry($iphost).AddressList[0].IPAddressToString
   } 
 ELSE { Throw "Specify either an IP V4 address or a hostname" }
}


$Servers = Get-ADComputer -Server $DCSRV -Filter {OperatingSystem -Like "*Server*"} -Properties *

$OutputReport = @()
[int64]$IntCounter=0
foreach ($Server in $Servers){
    $IntCounter+=1
    Write-Host $Server.Name " :  $IntCounter von " $Servers.Count
    $MYSRVInfo = '' |Select DNSHostname,DHCP,IPAddress,IPSubnet,Pingable,PWAge,OperatingSystemVersion,
    $MYSRVInfo.DNSHostname = $Server.DNSHostName
    if ($Server.DNSHostName) {$MYSRVInfo.IPAddress = Get-DnsEntry($Server.DNSHostName)}
    $MYSRVInfo.PWAge = $(New-TimeSpan -Start $([datetime]::FromFileTime($Server.pwdLastSet)) -End (get-date)).Days
    $MYSRVInfo.OperatingSystemVersion = $Server.OperatingSystemVersion
    $MYSRVInfo.Service_Pack = $Server.OperatingSystemServicePack
    try {
$IPCFG=Get-WmiObject -ComputerName $MYSRVInfo.IPAddress Win32_NetworkAdapterConfiguration -Properties IPAddress,IPSubnet,DHCPEnabled -ErrorAction Stop|?{$_.IPAddress -match $MYSRVInfo.IPAddress}
$MYSRVInfo.IPSubnet=$IPCFG.IPSubnet[$IPCFG.IPAddress.IndexOf($MYSRVInfo.IPAddress)]
$MYSRVInfo.DHCP=$IPCFG.DHCPEnabled
} catch {
$MYSRVInfo.IPSubnet='NOWMI'
$MYSRVInfo.DHCP='NOWMI'
}
    $MYSRVInfo.IPSubnet = 
    $OutputReport +=$MYSRVInfo
    if ($IntCounter % 20 -eq 0) {
        $OutputReport|Export-Csv -NoTypeInformation -Delimiter ';' -Path $reportfilename
        }
}

$OutputReport|Export-Csv -NoTypeInformation -Delimiter ';' -Path $reportfilename

# How To Fix now a certain Subnet from the Report

$ipscopetofixregex='10.1.2.*'
$rightsubnet='255.255.254.0'

# Filter now your Report 

$srvkaputt=Import-Csv -Delimiter ';' $reportfilename|?{($.IPAddress -match $ipscopetofixregex) -and ($_.IPSubnet -ne $rightsubnet) -and ([int]$_.DHCP -ne 1) -and ($_.DHCP -ne 'NOWMI')}

# Use WMI to fix it up - but be aware this code kills fixed IPv6 addresses and interrupt network traffic "slightly"

$srvkaputt|%{
    $ip=$_.IPAddress
    start-job -Args $_.IPAddress,$rightsubnet -scriptblock {
        param($ip,$sub)
        $IPCFG=(Get-WmiObject -ComputerName $ip Win32_NetworkAdapterConfiguration|?{$_.IPAddress -match $ip})
        $IPSUBNET=[string[]]($IPCFG.IPSubnet.Clone()|?{$_ -match "^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$"})
        $IPADDRES=[string[]]($IPCFG.IPAddress.Clone()|?{$_ -match "^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$"})
        $IPSUBNET[$IPADDRES.IndexOf($ip)]='$sub'
        $IPCFG.EnableStatic($IPADDRES,$IPSUBNET)
        }
    }

# Check with Get-Job maybe hunged jobs after a while and Kill them Get-Job|Remove-Job -f 

Montag, 2. Mai 2016

Delete huge folder structures where 260 character limit will stops you


Get annoyed by this fricking stupid path length limit of 260 characters when you just want a huge Folder send down the digital Jordan.
I needed this script to kill a folder structure on a Netapp FAS over CIFS with alot of personal folders (old profiles) with alot messed up ACLs. Be sure that you run it with a user which is in Administrator group.

https://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx#maxpath

This PS script walk recursivly through huge folder structures and rename them beginning from top to down 0-9999 before delete them in reverse order.

function Kill-FilePathLimit ([string]$fatpath)
{
    $list=Get-ChildItem -Directory $fatpath
    if ($list) {
        0..$($list.count - 1)|%{
            try{
                Rename-Item $list[$_].FullName $("{0:D4}" -f $_) -ErrorAction Stop
            } catch {
                $AccessRule = new-object System.Security.AccessControl.FileSystemAccessRule $([System.Security.Principal.WindowsIdentity]::GetCurrent().Name,"FullControl","Allow")
                $ICH = New-Object System.Security.Principal.NTAccount([System.Security.Principal.WindowsIdentity]::GetCurrent().Name)
                $ACL=Get-Acl $list[$_].FullName
                $acl.SetOwner($ICH)
                Set-Acl $list[$_].FullName -AclObject $acl
                $acl.SetAccessRule($AccessRule)
                Set-Acl $list[$_].FullName
                Rename-Item $list[$_].FullName $("{0:D4}" -f $_) -ErrorAction Stop
            }
        }
        Get-ChildItem -Directory $fatpath|%{
            Kill-FilePathLimit $_.FullName
        }
    } else {
        Remove-Item -Recurse $fatpath -Force -Confirm:$false
    }
}

Freitag, 22. Januar 2016

Netapp snapmirror from 7-mode to c-mode (cdot) fails with 'Source volume "7modefiler:vol_X" contains 32-bit data'

Imagine you have to snapmirror volumes from a old 7-mode filer to a new cDot one, off-course you read all the Blog-Posts, KBs and documents about. You know you have to convert any 32bit aggregates to 64bit first by adding disks (because your Ontap is below 8.1.4P4 where you can do this without).

About 32bit to 64bit conversion read here ..
https://kb.netapp.com/support/index?id=1014790

If your imagination is not ready - here the commands to create a snapmirror between 7-mode and cdot.

On 7modefiler:

wrfile -a /etc/snapmirror.allow cmodefiler-svm

On cmodefiler:

vserver peer transition create -local-vserver cmodefiler-svm -src-filer-name 7modefiler

network interface modify cmodefiler-svm_cifs_lif1 -vserver cmodefiler-svm -firewall-policy intercluster

network ping -lif cmodefiler-svm_cifs_lif1 -lif-owner cmodefiler-svm -destination 7modefiler

volume create -volume cmodefiler-svm_7mode_vol_X -aggregate cmodefiler-N_aggr_SATA -size 2048GB -type DP -vserver cmodefiler-svm

snapmirror create -source-path 7modefiler:vol_X -destination-path cmodefiler-svm:cmodefiler-svm_7mode_vol_X -type TDP

snapmirror initialize -destination-path cmodefiler-svm:cmodefiler-svm_7mode_vol_X

snapmirror modify -destination-path cmodefiler-svm:cmodefiler-svm_7mode_vol_X -schedule daily

According documentation it should work - but it fails and 'log show' on your c-mode filer show this,

Time                Node             Severity      Event
------------------- ---------------- ------------- ---------------------------
1/22/2016 15:30:03  cmodefiler-N ERROR         smc.snapmir.init.fail: Initialize from source volume '7modefiler:vol_X' contains 32-bit data' to destination volume 'cmodefiler-svm:cmodefiler-svm_7mode_vol_x' failed with error 'Source volume "7modefiler:vol_X" contains 32-bit data. Data transfer from a volume containing 32-bit data is not supported.'. Relationship UUID 'c0a9b225-c113-11e5-9430-xxxxxxxxx'.

while your 7-mode 'vol status' show this

7modefiler*> vol status
         Volume State           Status            Options
           vol0 online          raid_dp, flex     root, create_ucode=on, maxdirsize=73379
                                32-bit
   vol_X       online          raid_dp, flex     create_ucode=on, maxdirsize=73379
                                sis
                                64-bit

I had the luck that 1 of 4 aggregates on 7modefiler allready was 64bit, and the volumes on this aggregate worked fine. I thought with a beer on my sofa about the issue and i remembered that this aggregate was converted by myself some months ago. So what was the difference, the snapshots on the working volumes where already cycled since the conversion.

Rarely known FunFact : 32bit Snapshots were not converted to 64bit while the aggregate and volume itself were converted - they stay 32bit data - you have to delete all older snapshots.


Luckily i 
didn't had to care because i still have the older snapshots on the previous snapmirror destination - if someone would need a backup of his file ndmpcopy would bring it back.

7modefiler*> snap delete -a vol_X

To preserve the in between created 64bit snapshots do it per Powershell

Get-NAVolume|Get-NaSnapshot|?{$_.created -le [datetime]$('01.21.2016')}|Remove-NaSnapshot -Confirm:$false

The failed Snapmirror attempt leave the destination volume in a "unusable" state, so i had to destroy it and recreate again.

volume offline -volume cmodefiler-svm_7mode_vol_X -vserver cmodefiler-svm

snapmirror delete -destination-path cmodefiler-svm:cmodefiler-svm_7mode_vol_X 

volume destroy -volume cmodefiler-svm_7mode_vol_X -vserver cmodefiler-svm -force true

volume create -volume cmodefiler-svm_7mode_vol_X -aggregate cmodefiler-N_aggr_SATA -size 2048GB -type DP -vserver cmodefiler-svm

snapmirror create -source-path 7modefiler:vol_X -destination-path cmodefiler-svm:cmodefiler-svm_7mode_vol_X -type TDP

snapmirror initialize -destination-path cmodefiler-svm:cmodefiler-svm_7mode_vol_X

et voila Snapmirror does finaly what it should do.

cmodefiler-N::> snapmirror show
                                                                       Progress
Source            Destination Mirror  Relationship   Total             Last
Path        Type  Path        State   Status         Progress  Healthy Updated
----------- ---- ------------ ------- -------------- --------- ------- --------
7modefiler:vol_X
            TDP  cmodefiler-svm:cmodefiler-svm_7mode_vol_X
                              Uninitialized
                                      Transferring   22.30GB   true    01/22 16:27:42

If this article helped you - leave a comment.

Freitag, 23. Oktober 2015

Timestamped Logfiles in Powershell (even for long running commands)

Anyone who writes some PS Scripts which should run automated want to know what happens when, especial when Shit Happens. Logfiles save your ass - because when you know what went wrong it is easier to find who caused it.

I used several aproaches in the past, Using Out-File -Append is working fine too for a "quick info" but here my favorite using the .Net Streamwriter which is the fastest and most reliable way.

1. Define your Logfile, here i stamp it with DAY only, be aware this approach will overwrite your file with every run if has the same name - if you want to run it more than once per day just put a more detailed timestamp ("yyyyMMdd-hhmm") in it.

$LogfileName = $(-join('c:\_Script\',$(Get-Date -Format "yyyyMMdd"),'_MyScript.log'))
$global:Logfile = [System.IO.StreamWriter] $LogfileName
$Logfile.AutoFlush = $true

2. Define a function for "quick" entrys.

function LogEntry ($Log) {@($Log)|%{
   if ($_) {
      $Logfile.WriteLine((Get-Date -Format 'yyyy-MM-dd HH:mm:ss:fff ') + $_.ToString())
         }
      }
   }

3. How to use it ..

LogEntry("My Script was started")

Variables can put in ..

$user=&'whoami'
LogEntry("I run under the Account $user")

Be aware that when you want to log a property etc you have to enclose the variable with $() ...

$vm=get-view -type VirtualMachine Filter @{"Name"=$vmname}
LogEntry "MyScript is messing up the VM $($vm.Name) which has Status $($vm.Runtime.PowerState) ."

If your output has several lines ...

Set-NaCifsShareAcl -User $user -Share $share -AccessRights 'Full Control' -OutVariable Log -ErrorAction Stop
LogEntry($Log|Out-String -Stream)

If you dont trust your Command use it in try catch and get the Errormessage in your Logfile.

try {
   $data = Import-CSV '\\fileserver\mydata.csv' -ErrorAction Stop
   LogEntry("Importing Data from Share went fine, got $($data.Count) entries.")
   } catch {
   LogEntry("Importing Data from Share went wrong with $($_.Exception.Message) .")
   }

This do his job in most cases, and you get usefull informations in your log. 

4. But how about when you start some long running command like a backuptask from command line. You can capture the output in a variable and enter it in the log - but the caveeat is that the entries will only show up AFTER the command is done and all lines will share the timestamp when it was finished. In worst case you have a hanging command/process and you have no glue which state it has.

So how to fill up the logfile while the command is still running in realtime, so we can watch it with baretail or similar ?

We need another function, which does only the timestamping and is able to pipe and stream.

function TimeStampIt {process{"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss:fff ') $_"}}

Now we pipe the console output of our command through this function line by line to the WriteLine method of the Logfile Object. The "%" is a alias for "foreach".

My Labsample is a simple cmd File which ping local host.

&'C:\testping.cmd'|TimeStampIt|%{$Logfile.WriteLine($_)}

This is the result in your Logfile, you see every line has it own Timestamp, while the command is running you can watch the logfile per Baretail or similar.

2015-10-23 10:35:11:574  
2015-10-23 10:35:11:574  C:\Users\blablabla>ping 127.0.0.1 -n 5 
2015-10-23 10:35:11:590  
2015-10-23 10:35:11:590  Pinging 127.0.0.1 with 32 bytes of data:
2015-10-23 10:35:11:590  Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
2015-10-23 10:35:12:604  Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
2015-10-23 10:35:13:618  Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
2015-10-23 10:35:14:632  Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
2015-10-23 10:35:15:646  Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
2015-10-23 10:35:15:646  
2015-10-23 10:35:15:646  Ping statistics for 127.0.0.1:
2015-10-23 10:35:15:646      Packets: Sent = 5, Received = 5, Lost = 0 (0% loss),
2015-10-23 10:35:15:646  Approximate round trip times in milli-seconds:
2015-10-23 10:35:15:646      Minimum = 0ms, Maximum = 0ms, Average = 0ms

5. Dont forget the close the Logfile in the end of the Script.

LogEntry("Done my Job.")
$Logfile.Close()

I hope this will help you to make "good" and easy to troubleshoot scripts.

Freitag, 9. Oktober 2015

Notes about Netapp Ontap 8.3 cDot Simulator

Notes about Netapp Ontap 8.3 cDot Simulator

Preq:

- The Backendnetwork consist of 2 IPs per Clusternode, plan 1 IPs per Clusternode, 1 for cluster management, and 2 for SVMs - so 9 completly

- it create 4 interfaces, 2 cluster ones 1 you assign the "e0M" equivalent Managementport the 4th is the Service network
- Cluster network use on default EPIPA addresses 168.254.0.0/16

1. After deploying the OVA use vmkfstools -X 550g /vmfs/volumes/[DS]/[SIMVM]/[SIMVM]_1.vmdk to grow the harddrives which store the simulated harddrives. It works directly on ESX 5.1U2 - could be that it is nessesary to change the type to lsilogic (replace ide) by editing the [SIMVM]_1.vmdk file, and change it back after grow.

2. The Console of the filer VM switch on [Scroll lock] ("Rollen dear Germans) all the time, which blocks the command line.

3. The nodes need to "swipe" his config, press CTRL-C during boot when asked, use '4' to wipe the config  - a loooong reboot will be initiated which prepare the data disk for the virtual images.

4. We dont want to use this images, thatswhy we quit the wizzard. We have to set a admin password, unlock the diag user, and set a password for diag - use something easy here, like passwd12 because it is hard to enter it on the sloppy VM console, later you can change a secure one.

security login password
Please enter password: XXXXXXXX
Please enter a new password: XXXXXXXX
Please enter it again: XXXXXXXX
security login unlock -username diag
security login password -username diag
Please enter a new password: XXXXXXXX
Please enter it again: XXXXXXXX

Now we have to exit the shell and logon as diag user again, many other guides point to "systemshell local" or "system node run-console -node local" which does not work.

exit
login: diag
Password: XXXXXXXX

cd /sim/dev/,disks
sudo rm *
cd ..
sudo vsim_makedisks -n 14 -t 36 -a 0
sudo vsim_makedisks -n 14 -t 36 -a 1
sudo vsim_makedisks -n 14 -t 36 -a 2
sudo vsim_makedisks -n 14 -t 36 -a 3
ls ,disks/
sudo halt

By the way, if you wanna play arround with "hybrid" aggregates here is the point where you could choose a SATA drive type by using -t 37 (all other simulated disktypes can be checked by vsim_makedisk -h).

Reset the SIM, press again CTRL-C and choose 5 for maintenance when prompted. You can now check the created disks with "storage show disk" as we are still on the VM Console you need to enable "scroll lock" to check the whole output with the "up" key. We assign the first 3 disks.

disk assign v0.16 v0.17 v0.18
disk show
halt

It will message you some "unable to obtain owner" warning, just ignore it.

Reboot the SIM press again CTRL-C and wait until prompt. Enter selection 4 ‘Clean configuration and initialize all disks’ and answer ‘y’ to the two prompts.

5. Now as you have a nice Simulator a wizzard ask you to configure the management interface, your third vNIC on the VM.

Your "admin" user has no right to use SSH, the confusing thing it just close the ssh session after authentification. You have to assign the right for SSH by :

'security login create -user-or-group-name admin -role admin -application ssh  -authmethod password -comment "SSH Access for Admin"'

4Console ninjas it is 'sec[TAB]c[TAB]m[TAB][TAB]admin [TAB]ss[TAB][TAB]pa[TAB][TAB] [TAB] [TAB]c[TAB]"SSH Access for Admin"'

Now you can use your favorite ssh client (mine is portableKiTTY) to access the management IP, and get rid of the sloppy VM console.

Connect to your Management IP and run "cluster setup" to finish. The wizzard is quite straightforward.


6. A cluster with one node is quite boring. After deploying the 2. node and blow up the Sim-Disk vmdk, you have to change the SYS ID of the SIM to fit to the licences. When you boot the SIM the first time stop the Bootloader by pressing "some key - not Enter", in the Bootloader menu type this :

setenv SYS_SERIAL_NUM 4034389062
setenv bootarg.nvram.sysid 4034389062
boot

If you forget this step, and have allready booted the SIM once you can enter the "diag" mode (step 4) and delete the ",reservation" file in the ",disk" folder before you change the SYSID.

cd /sim/dev/,disks
sudo rm ,reserv*

7. For someone who is used 7-mode vFiler it is confusing that a SVM can get a Active Directory account without running a CIFS server, while the ADMIN SVM (your Cluster Instance) can run a NIS/LDAP client - but can not join a Domain neither sees their users, but the Admin-SVM can tunnel his requests to a SVM serving CIFS and beeing member or just beeing Member.

This joins a SVM to a Domain without running a CIFS Server :

vserver active-directory create -vserver [SVM] -domain [Domain FQDN] -account-name [CN of the Account] -ou ["OU=folder-3,OU=folder-2,OU=folder-1"|"CN=Computer"]

security login domain-tunnel create -vserver [SVM]

Now you can use the security login create command with -authmethod domain to provide Domainusers (really only users, not groups) access to the Cluster by SSH and HTTP (ontapi).

Crazy Powershell Oneliners

Here i present some 'useful' Oneliners - no need to understand them, will be extendet over the time

#Binding Order


Get IP Binding Order, it reads a registry key and print out the IPs

([WMIClass]"Root\Default:StdRegProv").GetMultiStringValue(2147483650,"SYSTEM\CurrentControlSet\services\Tcpip\Linkage","Bind").sValue|%{$(Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter "SettingID = '$($_.Substring(8))'").IPAddress}

For a lesser known enviroment you properly want to know if your Binding serves the NIC first which has the default Gateway.

([WMIClass]"Root\Default:StdRegProv").GetMultiStringValue(2147483650,"SYSTEM\CurrentControlSet\services\Tcpip\Linkage","Bind").sValue|%{$(Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter "SettingID = '$($_.Substring(8))'")|Select IPAddress, Description,DefaultIPGateway}

You should see the gateway on the first line, if not something is wrong.

Over Remote - this is surely usefull for healthchecks

$(Get-WmiObject -computer [COMPUTERNAME] -Namespace "Root\Default" -List | ?{$_.Name -eq "StdRegProv"}).GetMultiStringValue(2147483650,"SYSTEM\CurrentControlSet\services\Tcpip\Linkage","Bind").sValue|%{$(Get-WmiObject -computer [COMPUTERNAME] -Class Win32_NetworkAdapterConfiguration -Filter "SettingID = '$($_.Substring(8))'")|Select IPAddress, Description,DefaultIPGateway}

#Get all RSAT Tools

dism /Online /Get-Capabilities|Select-String Rsat|%{dism /Online /Add-Capability /CapabilityName:$($($_|Out-String).Split(':')[1].Trim())}