Archiv ‘Programmierung’

Mittwoch, 5. Juli 2017

Properties und Methoden eines PowerShell-Objektes anzeigen

Ich programmiere zwar seit einigen Jahren hie und da PowerShell-Scripts, aber bis heute wusste ich nicht, dass man Properties und Methoden eines PowerShell-Objektes derart einfach ausgeben kann. Die Web-Site msXfaq.de half weiter.

Properties

$var = Get-Date
$var | fl *
DisplayHint : DateTime
DateTime    : Dienstag, 29. Oktober 2013 00:16:08
Date        : 29.10.2013 00:00:00
Day         : 29
DayOfWeek   : Tuesday
DayOfYear   : 302
Hour        : 0
Kind        : Local
Millisecond : 229
Minute      : 16
Month       : 10
Second      : 8
Ticks       : 635186025682291672
TimeOfDay   : 00:16:08.2291672
Year        : 2013

Methoden

$var = Get-Date
$var | gm *
TypeName: System.DateTime

Name                 MemberType     Definition
----                 ----------     ----------
Add                  Method         datetime Add(timespan value)
AddDays              Method         datetime AddDays(double value)
AddHours             Method         datetime AddHours(double value)
AddMilliseconds      Method         datetime AddMilliseconds(double value)
AddMinutes           Method         datetime AddMinutes(double value)
AddMonths            Method         datetime AddMonths(int months)
AddSeconds           Method         datetime AddSeconds(double value)
AddTicks             Method         datetime AddTicks(long value)
AddYears             Method         datetime AddYears(int value)
CompareTo            Method         int CompareTo(System.Object value), int CompareTo(datetime value), int IComparable.CompareTo..
Equals               Method         bool Equals(System.Object value), bool Equals(datetime value), bool IEquatable[datetime].Equ..
IsDaylightSavingTime Method         bool IsDaylightSavingTime()
Subtract             Method         timespan Subtract(datetime value), datetime Subtract(timespan value)
ToFileTime           Method         long ToFileTime()
ToFileTimeUtc        Method         long ToFileTimeUtc()
ToLocalTime          Method         datetime ToLocalTime()
ToLongDateString     Method         string ToLongDateString()
ToLongTimeString     Method         string ToLongTimeString()
ToOADate             Method         double ToOADate()
ToSByte              Method         sbyte IConvertible.ToSByte(System.IFormatProvider provider)
ToShortDateString    Method         string ToShortDateString()
ToShortTimeString    Method         string ToShortTimeString()
ToString             Method         string ToString(), string ToString(string format), string ToString(System.IFormatProvider pr..
ToUniversalTime      Method         datetime ToUniversalTime()
DisplayHint          NoteProperty   Microsoft.PowerShell.Commands.DisplayHintType DisplayHint=DateTime
Date                 Property       datetime Date {get;}
Day                  Property       int Day {get;}
DayOfWeek            Property       System.DayOfWeek DayOfWeek {get;}
DayOfYear            Property       int DayOfYear {get;}
Hour                 Property       int Hour {get;}
Kind                 Property       System.DateTimeKind Kind {get;}
Millisecond          Property       int Millisecond {get;}
Minute               Property       int Minute {get;}
Month                Property       int Month {get;}
Second               Property       int Second {get;}
Ticks                Property       long Ticks {get;}
TimeOfDay            Property       timespan TimeOfDay {get;}
Year                 Property       int Year {get;}

Tags: , , , , ,
Labels: Programmierung

Keine Kommentare | neuen Kommentar verfassen

Mittwoch, 5. Juli 2017

Mit PowerShell ein Datum in einem spezifischen Format ausgeben

Heute habe ich an einem PowerShell-Script gearbeitet, welches Active Directory abfrägt und mir eine Liste von Benutzern ausgibt, die meinem Filter entsprechen.

Dabei interessierte mich auch das Attribut WhenCreated, welches angibt, wann ein Benutzerkonto erstellt wurde.

Mit dem Ausgabeformat dieses Feldes, welches als Datums-Objekt verarbeitet wird, war ich nicht zufrieden.

Doch wie gebe ich das Datum in einem von mir gewünschten Format aus? Nicht gerade trivial, aber es klappt:

...
$whenCreated = $objUser.whencreated
$whenCreate.GetDateTimeFormats()
...

So gibt man alle erdenklichen Variationen von Datumsformaten des aktuellen Datums-Objektes zurück. Nun muss man in der Liste nur noch die Zeilennummer des passenden Datumsformats finden, und integriert es dann folgendermassen in den Code. Ich habe mich dabei für die YYYY-MM-DD 00:00-Notation entschieden, welche in Zeile 103 ausgegeben wird:

...
$whenCreated = $objUser.whencreated
$whenCreatedFormatted = $whenCreate.GetDateTimeFormats()[103]
...

Via: How to format a DateTime in PowerShell?

Tags: , ,
Labels: Programmierung

Keine Kommentare | neuen Kommentar verfassen

Dienstag, 16. Dezember 2014

YCombinator Hacker News Evergreen-Artikel automatisiert zu Instapaper senden

Im November 2014 publizierte Ben Autrey auf Contextly eine Liste der am höchsten bewerteten Hacker News-Artikel aller Zeiten.

Da er in seinem Blog-Post nicht direkt auf die eigentlichen Artikel, sondern nur auf die Hacker News-Kommentarseite verwies, investierte ich gestern einige Zeit, um die eigentlichen Artikel automatisiert meinem Instapaper-Konto hinzuzufügen.

Das Ergebnis inklusive einer Textdatei mit allen Links auf die eigentlichen Artikel (urls-articles.txt) finden interessierte Zeitgenossen in meinem Github-Repository.

Tags: , , , , , , , ,
Labels: Programmierung

Keine Kommentare | neuen Kommentar verfassen

Donnerstag, 13. November 2014

Der Python-Paketmanager pip

Dann und wann programmiere ich anstelle mit PHP mit Python – wie gestern, als ich meinen Crawler websta-crawler für das (inoffizielle) Instagram-Frontend websta schrieb.

Für dieses Script greife ich auf die zwei Python-Module requests sowie BeautifulSoup zurück, welche bei einer Mac OS X-Standardinstallation nicht mit dabei sind.

Ein einfacher Weg, diese Module nachzurüsten, ist pip, eine Art Paketmanager für Python. Dieses Tool installiert sich folgendermassen:

$ wget https://bootstrap.pypa.io/get-pip.py

Anschliessend führt man das aus dem Internet heruntergeladene Script aus:

# python get-pip.py

Via: Installation

Sobald der Paketmanager ordnungsgemäss installiert wurde, reicht ein Einzeiler, um die zwei gewünschten Module nachzuinstallieren:

# pip install BeautifulSoup requests

Via: How to install multiple python packages at once using pip

Tags: , , , ,
Labels: Programmierung

Keine Kommentare | neuen Kommentar verfassen

Mittwoch, 29. Oktober 2014

Alle Seiten von PDF-Dateien unter Windows in Grafikdateien umwandeln

Kürzlich nahm ich mir vor, besonders visuell ansprechende Folien von Abschlusspräsentationen im Powerpoint-Format in einer Galerie zu sammeln, damit sich künftige Autoren an guten Beispielen inspirieren lassen können.

Als erstes sammelte ich alle Präsentationen, die mir auf unserem Netzlaufwerk bei der Durchsicht begegneten. Anschliessend öffnete ich jede Präsentation von Hand in Powerpoint und speicherte diese als PDF-Datei in einem zentralen Verzeichnis ab.

Da die Foliensätze nun in einem elektronischen Standardformat vorlagen, machte ich mich hinter ein Bash-Script, mit welchem ich alle Seiten der PDF-Dateien mittels ImageMagicks convert in einzelne Grafiken umwandeln konnte. Das Resultat:

# /bin/sh

DESTEXT="jpg"
DESTEXT="png"

echo "Starting up ..."
echo ""

echo "Working in directory $PWD ..."
echo ""

CONVERT=$(which convert)

if [ ! -f "$CONVERT" ]
then
echo "ERROR: convert binary 'convert' not found ($CONVERT). Aborting"
exit 1
fi

echo "Using convert binary at $CONVERT"
echo ""

# Ghostscript not in path in WIN32, won't succeed
# This is how imagemagick does it: http://trac.imagemagick.org/browser/ImageMagick/branches/ImageMagick-6/magick/nt-base.c?rev=13427
# https://www.google.ch/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=site%3Atrac.imagemagick.org%20gswin32c.exe
#GS32=$(which gswin32c.exe)
#GS64=$(which gswin64c.exe)
#if [ ! -f "$GS32" ] && [ ! -f "$GS64" ]
#then
#	echo "ERROR: Ghostscript binary 'gswin[32|64]c.exe' not found (32-bit: $GS32, 64-bit: $GS64). Aborting"
#	exit 1
#fi

#echo "All binaries exist, continuing conversion process."
#echo ""

echo "Using convert binary at $CONVERT"
echo ""

# http://unix.stackexchange.com/questions/9496/looping-through-files-with-spaces-in-the-names
find . -type f -iname "*.pdf" -print0 | while IFS= read -r -d '' PDF; do
echo "Converting $PDF ..."
SOURCE="$PDF"
DEST="$PDF.$DESTEXT"

CMD="\"$CONVERT\" -density 72 \"$SOURCE\" \"$DEST\""
echo "Command: $CMD"
eval $CMD
echo "Done"
echo ""
done

exit 0

Siehe auch:

Probleme

Fehlendes bash

Ich verwende die Git for Windows, um auch unter Windows auf eine bash zugreifen zu können. Git for Windows bringt unter anderem eine bash-Shell mit sich. Im Windows-Explorer öffnet man bash im aktuellen Verzeichnis, indem man nach einem Rechtsklick auf eine leere Fläche im Zielordner im Kontextmenu auf Git Bash klickt.

Fehlendes ImageMagick

ImageMagick steht auch als kompilierte Windows-Binaries zur Verfügung. Bei mir hat das Script mit folgendem Paket funktioniert:

C:\Users\USER>convert --version
Version: ImageMagick 6.8.9-6 Q16 x64 2014-07-22 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2014 ImageMagick Studio LLC
Features: DPC Modules OpenMP
Delegates: bzlib cairo freetype jbig jng jp2 jpeg lcms lqr pangocairo png ps rsv
g tiff webp xml zlib

Fehlendes Ghostscript

Wenn ImageMagick folgenden Fehler meldet …

convert.exe: FailedToExecuteCommand `"gswin32c.exe" -q -dQUIET -dSAFER -dBATCH -
dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 "-sDEV
ICE=pngalpha" -dTextAlphaBits=4 -dGraphicsAlphaBits=4 "-r72x72" "-sOutputFile=C
:/Users/USER/AppData/Local/Temp/magick-4444uMzVadN1QsOl%d" "-fC:/Users/USER/AppData/Local/Temp/magick-4444-MgLEhwrf1qK" "-fC:/Users/USER/AppData/Loc
al/Temp/magick-4444WnOaJKpe5I_Y"' (-1) @ error/utility.c/SystemCommand/2051.

… bedeutet dies, dass auf dem lokalen Windows-System die Installation von Ghostscript (gswin32c.exe) fehlt.

Ghostscript steht natürlich auch in Form von Windows-Binaries zur Verfügung und lässt sich mit einigen wenigen Mausklicks installieren.

Beim Debugging des oben genannten Problems drang ich tief in den Source Code ein, um die Stelle zu finden, wo ImageMagick herausfindet, wo die Ghostscript-Executables liegen:

Man schaue sich die Funktion NTLocateGhostscript() in nt-base.c genauer an: Die Pfade sind nicht hardkodiert, sondern werden aus der Windows-Registry ausgelesen. Dies bedingt, dass Ghostscript ordnungsgemäss installiert wurde.

Labels: Programmierung

Keine Kommentare | neuen Kommentar verfassen

Sonntag, 31. August 2014

Verzeichnis ohne Inhalt in SVN Repository einchecken

In meinem Falle wollte ich ein Cache-Verzeichnis in ein SVN Repository einchecken, ohne die aber in der Zwischenzeit darin abgelegten Cache-Dateien. Nichts leichter als das — SVN sieht auch für diesen Fall eine passende Kommandozeilenoption vor:

$ svn add --depth=empty cache

Via: Add directory structure to SVN, without files

Tags: ,
Labels: Programmierung

Keine Kommentare | neuen Kommentar verfassen

Donnerstag, 10. Juli 2014

Mit Python URLs dekodieren und JSON schön ausgeben

Ausgehend von dieser haarsträubenden URL der Credit Suisse …

https://www.credit-suisse.com/who_we_are/de/office_locator.jsp#%7B%22fs%22%3A%7B%22cid%22%3Anull%2C%22prid%22%3Anull%2C%22plid%22%3Anull%2C%22sid%22%3Anull%2C%22d%22%3A%5B0%2C0%2C0%2C0%2C0%2C0%2C0%2C0%2C0%2C0%5D%7D%2C%22ms%22%3A%7B%22c%22%3A%7B%22lat%22%3A46.94739121310314%2C%22lng%22%3A7.44410902261734%7D%2C%22z%22%3A18%7D%2C%22mk%22%3A%7B%22id%22%3A4451%7D%2C%22is%22%3A%7B%22id%22%3A%22mapPanel%22%2C%22ps%22%3A%7B%22id%22%3A4451%2C%22sid%22%3A11613%2C%22segid%22%3Anull%2C%22d%22%3A%5B0%2C0%2C0%2C0%2C0%2C0%2C0%2C0%2C0%2C0%5D%7D%7D%7D

… nachfolgend zwei Python Code-Snippets, mit welchen ihr die URL menschenlesbar machen könnt:

URLs dekodieren

urlClean = urllib.unquote(urlRaw).decode('utf8')

JSON schön ausgeben

json.dumps(json.loads(strJson), sort_keys=True, indent=4, separators=(',', ': '))

Tags: , , ,
Labels: Programmierung

Keine Kommentare | neuen Kommentar verfassen

Mittwoch, 18. Dezember 2013

Google crawlt einmal entdeckte URLs auf immer und ewig

Seit Monaten plagten mich die Log-Dateien eines von mir betreuten Web-Projektes: Bestimmte URLs wurden von Googlebot periodisch wiederkehrend aufgerufen, obwohl die Informationen dieser Web-Seiten vor langer Zeit deaktiviert worden waren (kurz: Die Objekte wie Personen und Referate waren nicht mehr in der Datenbank vorhanden und generierten beim Aufruf eine PHP-Exception, welche zwar abgefangen wurde, aber meine Log-Dateien vollmüllte) und das Script seit einigen Wochen einen HTTP 404-Fehler zurückgab.

Wie zum Teufel kam der Googlebot immer wieder auf diese verflixten URLs zurück?

Ich hatte eine verdächtige Subdomain des Projektes im Visier, welche eine archivierte Version der Web-Site bereitstellte. Deshalb passte ich die URLs auf dieser Web-Seite dort an und fügte ihnen eine GET-Variable hinzu, welche unmissverständlich aufzeigen sollte, ob der Googlebot die URLs von dieser Web-Site bezog. Leider stellte sich heraus, dass die Ursache des Übels nicht von dieser Web-Site herrührte.

Daraufhin wählte ich URLs aus, welche eine ganz bestimmte, möglichst einmalige Zeichenkette enthielten und gab diese in der Google-Suche ein. Tatsächlich lieferte Google die Seite der Web-Site als Resultat aus — obwohl die Seite seit Wochen HTTP 404 retournierte. Ein Blick auf den Zeitpunkt des Caches bestätigte, dass Google eine mehrere Wochen alte Version aufbewahrte, welche kurz vor dem Einbau der 404-Routine gecrawlt wurde.

Nun gut, sagte ich mir: Irgendwann einmal muss ja der Googlebot akzeptieren, dass eine URL permanent einen 404er zurückliefert und diese URL dann nicht mehr regelmässig anpingen. Falsch gedacht:

Once Googlebot finds and crawls a URL, they will periodically come back and crawl it again forever. Even after you remove the page and have been returning 404 status for years, Googlebot will still crawl the URL from time to time.

Quelle: Google Crawls my disabled products on my Magento website [closed]

So ist das. Gibt es also wirklich nichts, was ein besorgter Webmaster tun kann? Doch, durchaus:

I followed up on the 404 vs 410 thing with the team here. As mentioned by some others here & elsewhere, we have generally been treating them the same in the past.

However, after looking at how webmasters use them in practice we are now treating the 410 HTTP result code as a bit „more permanent“ than a 404. So if you’re absolutely sure that a page no longer exists and will never exist again, using a 410 would likely be a good thing. I don’t think it’s worth rewriting a server to change from 404 to 410, but if you’re looking at that part of your code anyway, you might as well choose the „permanent“ result code if you can be absolutely sure that the URL will not be used again. If you can’t be sure of that (for whatever reason), then I would recommend sticking to the 404 HTTP result code.

In the worst case, the 410 will be treated the same as a 404; in the best case it’ll be a bit quicker & stickier :-).

Quelle: Does it make sense to return a 410 instead of 404 when some page has been permanently removed?, Via: Does it make sense to return a 410 instead of 404 when some page has been permanently removed?

Ich passte also meinen try-catch-Block im Script an, welcher neu heisst:

...
header("HTTP/1.0 410 Gone");
...

Tags: , , , , ,
Labels: Programmierung

Keine Kommentare | neuen Kommentar verfassen

Mittwoch, 18. Dezember 2013

Den Netatmo PHP API-Client mit weniger strikten SSL-Anforderungen patchen

Vor einigen Tagen hörte mein Raspberry Pi-Dashboard auf, die Werte meiner Netatmo NWS01 Wetterstation für Apple iPhone und Android anzuzeigen.

Auf meinem lokalen Mac funktionierte das Dashboard hingegen problemlos; d.h. ich konnte mittels dem Netatmo PHP API-Client die JSON-Datei mit den aktuellen Messwerten wie Temperatur, Luftdruck und -feuchtigkeit abrufen.

Die genaue Ursache hinter dem Problem kenne ich bis heute nicht, doch ich vermute mit dem jetzigen Wissensstand, dass die Cyon-Ingenieure an der Konfiguration ihrer Server herumgewerkelt haben und dabei unter anderem das Root-Zertifikat entfernt haben, welches der Netatmo API-Client zur HTTPS-verschlüsselten Kommunikation mit den Netatmo-Servern verwendet.

Nachdem ich nämlich die Exception mittels vardump() genauer betrachtete, welche NACurlErrorType zurücklieferte, war der Fall schnell sonnenklar:

...
[message:protected] => SSL peer certificate or SSH remote key was not OK
...

Nun … gut! Was macht man da? Ich habe die Datei NAApiClient.php gepatcht, indem ich cURL mit der auf false gesetzten Option CURLOPT_SSL_VERIFYHOST sage, unverifizierte SSL-Zertifikate kommentarlos zu akzeptieren:

...
        else 
        {
            $opts[CURLOPT_HTTPHEADER] = array('Expect:');
        }
        
        $opts[CURLOPT_SSL_VERIFYHOST] = false;
        
        curl_setopt_array($ch, $opts);
...

Bei einer API wie Netatmo ist diese manuell herbeigeführte Schwachstelle zu verantworten. Ginge es um Mailverkehr oder Online-Banking, würde ich eine solche Option definitiv nicht aktivieren.

Tags: , , , , , , , ,
Labels: Programmierung

Keine Kommentare | neuen Kommentar verfassen

Donnerstag, 24. Oktober 2013

Mit PowerShell Dateien finden, die eine bestimmte Zeichenkette angehängt haben

Folgendes PowerShell-Script zeigt mir in einem Verzeichnis mit unzähligen PDF-Dateien diejenigen an, für welche es eine Version mit %NAMEN%.pdf sowie %NAMEN%-native.pdf gibt:

$duplicateIndicator = "-native"

function Get-ScriptDirectory {
  $Invocation = (Get-Variable MyInvocation -Scope 1).Value
  Split-Path $Invocation.MyCommand.Path
}

$scriptDir = Get-ScriptDirectory

$pattern = "*" + $duplicateIndicator + ".pdf"
Write-Host "Looking for $pattern ..."
Write-Host ""

$counter = 0
Dir $pattern | ForEach-Object {
	$counter++
	
	$duplicate = $_.name
	$original = $duplicate -replace $duplicateIndicator, ""
	$originalPath = $scriptDir + '\' + $original
	
	#Write-Host $duplicate
	#Write-Host $original
	
	#Write-Host "Looking for original file $originalPath"
	$fileExists = Test-Path $originalPath
	
	If ($fileExists) {
		Write-Host "Found duplicate for "
		Write-Host "    $original"
		Write-Host ""
	}
	
	#Dir $original
}

Write-Host "Scanned $counter file(s)."
Write-Host "Done."
Write-Host ""

Tags: , , , ,
Labels: Programmierung

Keine Kommentare | neuen Kommentar verfassen