Montag, 4. Dezember 2023

Dealing with "the authorization policy does not allow saved credentials" in RoyalTS

Having to type your password when connecting to RDP suxx, i regular use RoyalTS as RDP client which is even free for personal use but limited to 10 connections (not a hard one, use dynamic folders and clear them before save).

To deal with nasty PW prompts i wrote a script which integrates a task named "UseSavedCred" to your "Main" document usable as "Connect Task". 

Save it as PS1 and run it, if RoyalTS is running it stop it, and restart it after the install process.

Now you can choose the Task for "Connect Task" for the RDP Connections which pop up the credential window.




The "installed" script search in the sub processes of it an editable password field and type the password in it + press Enter. I did not test it with passwords with "<",">","|" or "&" character inside, as they often brocke sending them selves through the pipeline. 

Give me feedback into the comments.

Dienstag, 18. Januar 2022

Quick-n-dirty function to test a NTP Server per Powershell

.. quite simple - just to test if a ntp server works, if you need more accuracy than +/-9sec just match against ",\ (\+|-)00" 

function Test-NTP($ntpserver){
$pinfo=[System.Diagnostics.ProcessStartInfo]::new("$($env:SystemRoot)\system32\w32tm.exe",@("/stripchart","/computer:$ntpserver","/dataonly","/samples:1"))
$pinfo.RedirectStandardOutput = $true
$pinfo.UseShellExecute = $false
$ntptestproc=[System.Diagnostics.Process]::new()
$ntptestproc.StartInfo=$pinfo
$ntptestproc.Start()|Out-Null
$ntptestproc.WaitForExit()
return $ntptestproc.StandardOutput.ReadToEnd() -match ",\ (\+|-)0"
}

Dienstag, 7. September 2021

Loseless Merging Directories with Powershell

 

I needed a nice little function for merging directories without loosing documents in case of collisions of paths. Because i needed this for tidying up a hell of messed up homedrives i didnt care about any ACL etc.

function MoveCollisionFree([string]$srcdir,[string]$dstdir){
$srcdir = $srcdir.TrimEnd('\')
$dstdir = $dstdir.TrimEnd('\')
$srcRegEx=[regex]::Escape($srcdir)

[System.IO.Directory]::GetDirectories($srcdir).ForEach({
$DestPath=$_ -replace($srcRegEx,$dstdir)
if([System.IO.Directory]::Exists($DestPath)){
MoveCollisionFree -srcdir $_ -dstdir $DestPath
}else{[System.IO.Directory]::Move($_,$DestPath)}
})
[System.IO.DirectoryInfo]::new($srcdir).GetFiles().ForEach({
$DestFile=[System.IO.FileInfo]::new($($_.FullName -replace($srcRegEx,$dstdir)))
if($DestFile.Exists){
if($DestFile.LastWriteTime -ge $_.LastWriteTime){
$_.MoveTo("$($DestFile.Directory.FullName)\$($_.BaseName)_older_from_$($_.LastWriteTime.ToString('yyyy-MM-dd'))$($_.Extension)")
}else{
$NewFileName=$DestFile.FullName
$DestFile.MoveTo("$($DestFile.Directory.FullName)\$($_.BaseName)_older_from_$($DestFile.LastWriteTime.ToString('yyyy-MM-dd'))$($_.Extension)")
$_.MoveTo($NewFileName)
}
}else{$_.MoveTo($DestFile.FullName)}
})
Remove-Item $srcdir -Recurse -Force -Confirm:$false
}

Donnerstag, 22. Oktober 2020

How to extend NABox with Capacity information without having OCUM - my first python


Monitoring a Netapp is important, the "unofficial" Monitoring NAbox is installed like a slice of cake.


If you never heard about it - check it out here .. https://nabox.org/

But it does not collect the "capacity" information of his objects (volumes and aggregates) without the help of a OCUM (or Active IQ Unified Manager) . 

Instead of installing another Appliance you can collect the needed data from Netapp Systems running Ontap 9.6+ by NAbox itself per REST-API.

First create a authentification certificate (which is usable for Powershell too, see my next post) : 

Log into the NABox with SSH - (root:NetappGrafanaVA are the default login credentials). 

mkdir /opt/myontapcol/

openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout /opt/myontapcol/ontapkey.key -out /opt/myontapcol/ontap.pem -subj "/C=DE/ST=WONDERLAND/L=EMERALDCITY/O=IT/CN=nabox"

BE AWARE OF "CN=nabox" this will be the user which we configure in  the next step.

cat /opt/myontapcol/ontap.pem

connect with a 2nd SSH Shell to the Netapp and run this command, take the output from above into clipboard, you need to paste it.

security certificate install -type client-ca -vserver mycluster

it sometimes needs 3 "enter".

security ssl modify -client-enabled true -vserver mycluster

security login create -user-or-group-name nabox -application http -authentication-method cert -role readonly -vserver mycluster

your netapp answers now REST API requests,

You can test it on the nabox shell with

curl -s --key /opt/myontapcol/ontap.key --cert /opt/myontapcol/ontap.pem -k https://ontap-a.acme.corp/api/storage/aggregates

Now lets a script feed the NABox with data, except the python extension jsonpickle the nabox have all neccesary things allready installed.

pip install -U jsonpickle

I uploaded the script here .. naboxcapacol unzip the file open up the naboxcapacol.py file with notepad.

[UPDATE - Newer NA Boxes do not use the port 2004 and use 2013 for pickles counter - find the config file with ps -au|grep carbon and grep -A 5 ^.pick /etc/go-carbon/go-carbon.conf  ]


Copy the script into the file and save it.

nano /opt/myontapcol/ontapcapacol.py

#make it executable

chmod +x /opt/myontapcol/ontapcapacol.py

#and let it run every 5min

crontab -e

*/5 * * * * /opt/myontapcol/ontapcapacol.py >> ~/cron.log 2>&1

# after 1h take a look for some of the data 

https://nabox/graphite/?width=800&lineMode=connected&showTarget=mgtechhead.*.*.aggregates.*.volumes.*.used&height=600&target=mgtechhead.*.*.aggregates.*.volumes.*.used

You can now import my "simple" capacity dashboard ontapcapacol.json from the zip or just create your own. I created this for a customer who is not using so much qtrees.

The dashboards which came with harvest are not connecting volume and aggregate together, if you want to have the data here you have to alter the script in a way that it pumps the data to this paths.

netapp/capacity/$Group/$Cluster/svm/$SVM/vol/$Volume
netapp/capacity/$Group/$Cluster/svm/$SVM/vol/$Volume/afs_total
netapp/capacity/$Group/$Cluster/svm/$SVM/vol/$Volume/snapshot_reserve_total
netapp/capacity/$Group/$Cluster/svm/$SVM/vol/$Volume/snapshot_used_percent
netapp/capacity/$Group/$Cluster/svm/$SVM/vol/$Volume/afs_avail
netapp/capacity/$Group/$Cluster/svm/$SVM/vol/$Volume/afs_daily_growth_rate
netapp/capacity/$Group/$Cluster/svm/$SVM/vol/$Volume/overwrite_reserve_total
netapp/capacity/$Group/$Cluster/svm/$SVM/vol/$Volume/snapshot_reserve_avail
netapp/capacity/$Group/$Cluster/svm/$SVM/vol/$Volume/afs_used_percent
netapp/capacity/$Group/$Cluster/svm/$SVM/vol/$Volume/overwrite_reserve_used
netapp/capacity/$Group/$Cluster/svm/$SVM/vol/$Volume/overwrite_reserve_avail
netapp/capacity/$Group/$Cluster/svm/$SVM/vol/$Volume/actual_volume_size
netapp/capacity/$Group/$Cluster/svm/$SVM/vol/$Volume/afs_used_per_day
netapp/capacity/$Group/$Cluster/svm/$SVM/vol/$Volume/snapshot_reserve_used
netapp/capacity/$Group/$Cluster/svm/$SVM/vol/$Volume/total
netapp/capacity/$Group/$Cluster/svm/$SVM/vol/$Volume/afs_used
netapp/capacity/$Group/$Cluster/svm/$SVM/vol/$Volume/quota_committed_space
netapp/capacity/$Group/$Cluster/node/$Node/aggr/aggr_$Aggregate
netapp/capacity/$Group/$Cluster/node/$Node/aggr/aggr_$Aggregate/compression_space_savings
netapp/capacity/$Group/$Cluster/node/$Node/aggr/aggr_$Aggregate/dedupe_space_savings
netapp/capacity/$Group/$Cluster/node/$Node/aggr/aggr_$Aggregate/snapshot_reserve_total
netapp/capacity/$Group/$Cluster/node/$Node/aggr/aggr_$Aggregate/size_used
netapp/capacity/$Group/$Cluster/node/$Node/aggr/aggr_$Aggregate/size_used_per_day
netapp/capacity/$Group/$Cluster/node/$Node/aggr/aggr_$Aggregate/size_total
netapp/capacity/$Group/$Cluster/node/$Node/aggr/aggr_$Aggregate/size_available
netapp/capacity/$Group/$Cluster/node/$Node/aggr/aggr_$Aggregate/daily_growth_rate
netapp/capacity/$Group/$Cluster/node/$Node/aggr/aggr_$Aggregate/snapshot_reserve_avail
netapp/capacity/$Group/$Cluster/node/$Node/aggr/aggr_$Aggregate/compression_space_savings_percent
netapp/capacity/$Group/$Cluster/node/$Node/aggr/aggr_$Aggregate/dedupe_space_savings_percent
netapp/capacity/$Group/$Cluster/node/$Node/aggr/aggr_$Aggregate/space_total_committed
netapp/capacity/$Group/$Cluster/node/$Node/aggr/aggr_$Aggregate/size_used_percent
netapp/capacity/$Group/$Cluster/node/$Node/aggr/aggr_$Aggregate/snapshot_reserve_used


Known issue - if you move a volume you have to delete the counters 

rm /opt/graphite/storage/whisper/mgtechhead/*/*/aggregates.[former_aggregate].volumes.[volume_name]/*
rmdir /opt/graphite/storage/whisper/mgtechhead/*/*/aggregates.[former_aggregate].volumes.[volume_name]

Freitag, 1. November 2019

Add a Netapp LUN as VM Datastore per Powershell

You can speak Powershell to Netapp and VMware, so adding a LUN as Datastore should not a problem, despite the fact that Netapp Powershell command get-nclun does not deliver the worldwidename of the lun per default.

But according this KB from Netapp a LUN NAA is just a prefix + serial ascii to hex converted.

https://kb.netapp.com/app/answers/answer_view/a_id/1033595/~/how-to-match-a-luns-naa-number-to-its-serial-number-

This is "stupid" adding all LUNs as Datastore using the filename of the LUN as Suffix.

Get-NcLun|select Node,Vserver,Path,
 @{N='NAA';E={"naa.600a0980$(-join ($_.SerialNumber.ToCharArray()|%{'{0:x}' -f $([byte][char]$_)}))"}}|%{
  get-vmhost esxserver|New-Datastore -Vmfs -Name "VMFS_$($_.Path.Split('/')[2])" -Path $_.NAA
  }

Maybe better declaring a function to make Code better readable ...

function Convert-ASCIItoHEX_STRING ([string]$inputstring){
return $(-join ($inputstring.ToCharArray()|%{'{0:x}' -f $([byte][char]$_)}))
}

Get-NcLun|select Node,Vserver,Path,
 @{N='NAA';E={"naa.600a0980$(Convert-ASCIItoHEX_STRING $_.SerialNumber)"}}|%{
  get-vmhost esxserver|New-Datastore -Vmfs -Name "VMFS_$($_.Path.Split('/')[2])" -Path $_.NAA
  }

I hope this comes handy sometimes ..

Mittwoch, 4. Juli 2018

How to recover access to a Brocade SAN switch after password dementia.

There are already too much blog posts around ? Most of them just talk about going onsite - using serial cable or "back door" user which are mostly disabled.

When the default password 'fibranne' for the root user did not help you, but you have still access to another switch in the fabric, this ist the way to push the password database from one switch you can access to the one you locked yourself out.

distribute -p PWD -d [#SwitchID]

#SwitchID is the decimal number in the first row in fabricshow output.

After this you can logon with the same password you know from switch A.

This is also a fine way to prevent to setup every password for admin, user, factory etc. by hand. Just setup one switch in the fabric properly and "push" the settings to each - or to configure fresh passwords FAST in a environment.

Mittwoch, 7. Februar 2018

Get Fibrechannel WWPNs and alot other HW Info from Fujitsu iRMC4 per Powershell

Pssst .. wanna get ALL the cool hardware info you see on an iRMC4 WebGui in a Powershell object ?
If you need even the fibrechannel stuff, you won't get it by REST,CIM or WSMAN - i deep-dived some days into all kind of documentations, wasted alot of time in enumerating and finally gave up, the only way seems to be get it from the WebGui - shame on Fujitsu - DELL do it better, see my next post.

This quick-n-dirty shit worked fine for me for PRIMERGY RX2540 M1, PRIMERGY RX2540 M2, PRIMERGY RX4770 M2 and PRIMERGY RX300 S8 - nice for report all MAC, WWPNs, Serials, Firmware etc ... if you use it let me know.

function Get-iRMC_HWInfo($irmcname,$irmcuser,$irmcpw)
{
    $rsacred=New-Object System.Management.Automation.PsCredential($irmcuser,$(ConvertTo-SecureString -String $irmcpw -AsPlainText -force)) 
    $body = @{APPLY = 99;P99='Login'}
    $irmcwebreq=Invoke-WebRequest "http://$irmcname/login" -SessionVariable irmcsession -Credential $rsacred -Method Post -Body $body
    $hwinfo=$($irmcwebreq.AllElements|?{$_.TagName -eq 'TR'}|?{$_.innerText -match '^System Type|^Serial|^System GUID|^System Name|^System\ O/S'}).innerText    
    $networkinventorylink=$($irmcwebreq.Links|?{$_.innerHTML -eq 'Network Inventory'}).href
    $irmcwebreq2=Invoke-WebRequest "http://$irmcname/$networkinventorylink" -WebSession $irmcsession 
    $tabellen=$irmcwebreq2.ParsedHtml.getElementsByTagName("TABLE")
    $nictabelle=$tabellen|?{$_.summary -match 'Ethernet'}
    $fctabelle=$tabellen|?{$_.summary -match 'Fibre'}
    $nicports=@()
    foreach($datarow in $nictabelle.rows){
        if($datarow.cells[0].tagName -eq "TD"){
            $nicports+=@{Enabled=$datarow.cells[0].innerHTML -match 'ok.gif';
                SlotID=$datarow.cells[1].innerText;
                FunctionID=$datarow.cells[2].innerText;
                PortID=$datarow.cells[3].innerText;
                Firmware=$datarow.cells[5].innerText;
                OpROM=$datarow.cells[6].innerText;
                Interface=$datarow.cells[7].innerText;
                VenID=$datarow.cells[9].innerText;
                DevID=$datarow.cells[10].innerText;
                SubVenID=$datarow.cells[11].innerText;
                SubDevID=$datarow.cells[12].innerText;
                MAC=$datarow.cells[14].innerText
            }
        }
    }

    $fcports=@()
    foreach($datarow in $fctabelle.rows){
        if($datarow.cells[0].tagName -eq "TD"){
            $fcports+=@{Enabled=$datarow.cells[0].innerHTML -match 'ok.gif';
                SlotID=$datarow.cells[1].innerText;
                FunctionID=$datarow.cells[2].innerText;
                PortID=$datarow.cells[3].innerText;
                Firmware=$datarow.cells[5].innerText;
                OpROM=$datarow.cells[6].innerText;
                Interface=$datarow.cells[7].innerText;
                VenID=$datarow.cells[9].innerText;
                DevID=$datarow.cells[10].innerText;
                SubVenID=$datarow.cells[11].innerText;
                SubDevID=$datarow.cells[12].innerText;
                WWNN=$datarow.cells[14].innerText;
                WWPN=$datarow.cells[15].innerText}
            }
        }
    return [pscustomobject]@{
        SysType=$hwinfo[0].Split(':')[1];
        SysSerial=$hwinfo[1].Split(':')[1];
        SysGUID=$hwinfo[2].Split(':')[1];
        SysName=$hwinfo[3].Split(':')[1];
        SysOS=$hwinfo[4].Split(':')[1];
        nicports=$nicports;
        fcports=$fcports
 }

}

Yeah thats all folks - ugly quick-n-dirty.