Archive for the ‘Shell’ Category

Windows 10 geht im kleinsten Detail die Puste aus–oder warum werden meine Icons im Windows Explorer falsch dargestellt?

31 Oktober 2015

Wie erbärmlich ist das denn? Windows 10 liefert von Haus aus OneDrive mit aus. Die Sache an sich ist schon zweifelhaft aber jetzt kommt das Highlight. Um den Status der Dateien welche Offline, Online, gesynct werden usw. anzeigen zu können, werden zum Icon der Datei sogenannte Icon Overlays benutzt. OneDrive bringt schon fünf mit, vier sind von Windows generell für den Explorer reserviert. Sind also neun Overlay Icons. Dumm ist jetzt nur, dass bei Windows 10 aus unerfindlichen Gründen nur maximal 15(!) Icon Overlays vorgesehen sind. Wer jetzt Dropbox oder ähnliches installiert…

https://support.microsoft.com/en-us/kb/3106961

https://msdn.microsoft.com/en-us/library/windows/desktop/cc144123(v=vs.85).aspx

Suchen und Ersetzen in Verknüpfungen (.LNK-, .URL- und .WebSite-Dateien) auf dem Desktop automatisieren

20 September 2015

Angenommen, man hat einen üblichen Desktop vor sich. Dieser ist mit zig Dateien und Verknüpfungen übersäht. Wenn man dann wissen möchte, welcher Link auf ein bestimmtes Verzeichnis verweist, dann kann das schnell in Arbeit ausarten. Wenn man dann noch etwas ersetzen muss, kann man in vielen Umgebungen Spaß mit fehlender UAC Unterstützung unter Windows haben. Am Ende flucht man, warum man nicht mal mit Admin-Rechten einen einfachen Link aktualisieren kann.

In allen diesen Fällen hilft wie immer Omo, nö Powershell wars.

Zunächst gilt es alle Verknüpfungen auf dem Desktop zu finden. Man erzeugt zunächst ein Shell-Objekt:

$shell = New-Object –ComObject Shell.Application

Nun benötigt man die Links vom Desktop. Man könnte nun direkt auf den Pfad des aktuellen Benutzers verweisen aber noch eleganter ist es, sich vom System den Pfad geben zu lassen:

$desktop = $shell.Namespace(0x10)

Wenn man sich $desktop anschaut erhält man:

Title                      : Desktop
Application                : System.__ComObject
Parent                     :
ParentFolder               : System.__ComObject
Self                       : System.__ComObject
OfflineStatus              :
HaveToShowWebViewBarricade : False
ShowWebViewBarricade       : False

Nicht sehr überzeugend oder? Besser wird es damit:

PS > $desktop.Self

Application  : System.__ComObject
Parent       : System.__ComObject
Name         : Desktop
Path         : C:\Users\Benutzer\Desktop
GetLink      :
GetFolder    : System.__ComObject
IsLink       : False
IsFolder     : True
IsFileSystem : True
IsBrowsable  : False
ModifyDate   : 17.09.2015 17:31:32
Size         : 0
Type         : Dateiordner

Man bekommt also mittels $desktop.Self.Path den aktuellen Pfad zum Desktop. Damit kann man nun etwas anfangen, z. B. die Verknüpfungen ermitteln:

Get-ChildItem $desktop.Self.Path -Filter *.lnk

Aber Moment, wer sich vielleicht wundert, warum nicht alle Verknüpfungen auftauchen, die ein Benutzer auf seinem Desktop hat, dem sei gesagt, es gibt auch einen öffentlichen Desktop, der für alle Benutzer gilt. Obiger Namespaceaufruf hatte nur den Desktop des aktuellen Benutzers zurückgegeben. Die öffentliche Variante erhält man so:

$publicDesktop = $shell.Namespace(0x19)

wenn man sich hier $publicDesktop.Self.Path anschaut erhält man

C:\Users\Public\Desktop

Kurz noch als Erklärung zu 0x10 bzw. 0x19, dabei handelt es sich um Konstanten aus den Shell Special Folders, eine Auflistung ist hier zu finden: https://msdn.microsoft.com/en-us/library/windows/desktop/bb774096(v=vs.85).aspx. Da es wie immer eine Tortur ist, eine aktuelle Beschreibung in der MSDN zu finden, sei noch diese Methode genannt, um alle möglichen Werte zu sehen:

0..250| % { $v=($shell.NameSpace($_)).Self; if ($v -ne $null) { New-Object psObject -Property @{Index=$_; Name=$v.Name; Path=$v.Path}} }

Weiter beim eigentlichen Thema. Nun wird es langsam was, so bekommt man beides zusammen:

$dl = Get-ChildItem $desktop.Self.Path -Filter *.lnk
$dl += Get-ChildItem $publicDesktop.Self.Path -Filter *.lnk

Nun enthält $dl tatsächlich alle LNK-Dateiverweise. Jetzt also zum Inhalt der Verknüpfungen. Da LNK-Dateien ein eigenwilliges Binärformat haben, muss dieses speziell gelesen werden. Aber die Shell-Klassen bieten hier auch Unterstützung. Dazu gibt es die Methode ParseName, welche so angewendet werden kann:

$fileItem = $desktop.ParseName($dl[0].Name)
$fileItem.IsLink

Erst jetzt weiß man, ob die LNK-Datei wirklich eine Linkdatei ist. Wenn dem so ist, kann man hiermit das Link-Objekt instanzieren:

$sc = $fileItem.GetLink

$sc enthält, dann z. B. Daten wie diese:

Path             : C:\Windows\SysWOW64\cmd.exe
Description      :
WorkingDirectory : C:\windows\SysWOW64
Arguments        :
Hotkey           : 0
ShowCommand      : 1
Target           : System.__ComObject

Hier kann man nun konkret auch den Pfad oder das Working-Directory ändern. So kann man z. B. im obigen Beispiel den Pfad von SysWOW64 in System32 ändern, welches dann so aussieht:

$sc.Path = $sc.Path.Replace("SysWOW64", "System32")

Damit diese Änderung aber tatsächlich auch auf der Platte landet, muss die Änderung noch gespeichert werden:

$sc.Save

Leider hat die bisherige Vorgehensweise ein paar Probleme. Denn das obige Zusammenführen des User- und des Öffentlichen-Desktop, macht Probleme. denn ParseName verlangt immer den reinen Dateinamen ohne Pfad, was dann bei Anwendung obiger Methode bei öffentlichen Desktopobjekten beim Aufruf über $desktop nicht zum Ziel führt. Man sollte also $dl nach dem Pfad abfragen und entsprechend $desktop oder $publicDesktop verwenden.

if ($_.DirectoryName –eq $desktop.Self.Path) {
  $fi = $desktop.ParseName($_)
} else {
  $fi = $publicDesktop.ParseName($_)
}

Somit hat man nun in $fi immer das richtige FileItem und kann so weiterverfahren:

if ($fi.IsLink) {
  $sc = $fi.GetLink
  $sc.Path = $sc.Path.Replace("ALT", "NEU")
  $sc.Save

}

Übrigens kann man nicht nur LNK-Dateien sondern auch .URL und .WebSite –Dateien damit bearbeiten, welche etwas abgewandelte Link-Dateien sind. Von der Verarbeitung jedoch ändert sich nichts, man geht direkt auf die Pfad-Eigenschaft los und ändert diese.

So da es nun wie so oft etwas unübersichtlich wurde, alles nochmal geballt, inkl. .URL und .WEBSITE:

$shell = New-Object –ComObject Shell.Application
$desktop = $shell.Namespace(0x10)
$publicDesktop = $shell.Namespace(0x19)
$dl = Get-ChildItem $desktop.Self.Path -Filter *.lnk
$dl += Get-ChildItem $desktop.Self.Path -Filter *.url
$dl += Get-ChildItem $desktop.Self.Path -Filter *.website
$dl += Get-ChildItem $publicDesktop.Self.Path -Filter *.lnk
$dl += Get-ChildItem $publicDesktop.Self.Path -Filter *.url
$dl += Get-ChildItem $publicDesktop.Self.Path -Filter *.website
$dl | foreach {
    if ($_.DirectoryName –eq $desktop.Self.Path) {
         $fi = $desktop.ParseName($_.Name)
    } else {
         $fi = $publicDesktop.ParseName($_.Name)
    }
    if ($fi.IsLink) {
       $sc = $fi.GetLink
       $sc.Path = $sc.Path.Replace("ALT", "NEU")
       $sc.Save()
    }
}

Falls man eine Fehlermeldung wie z. B. diese bekommt

Es ist nicht möglich, eine Methode für einen Ausdruck aufzurufen, der den NULL hat.
In Zeile:21 Zeichen:8
+        $sc.Path = $sc.Path.Replace("ALT", "NEU")
+        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

sollte man sich überlegen, das Script vielleicht als Admin auszuführen, denn es ist nicht so gern gesehen, wenn einfache Benutzer den Öffentlichen Desktop verändern!

Windows 8 Godmode

19 Januar 2013

Wenn man mal wieder auf der Suche nach einem bestimmten Zusatzprogramm unter Windows ist, kommt einem der GodMode von Windows zuhilfe.

Auch unter Windows 8 funktioniert dieser noch, einfach

shell:::{ED7BA470-8E54-465E-825C-99712043E01C}

im Windows Explorer in der Adresszeile eingeben und los gehts.

Für uns DOSler gilt:

start shell:::{ED7BA470-8E54-465E-825C-99712043E01C}

und die Party beginnt.

Weitere Infos hier: http://support.microsoft.com/kb/978780/de und hier http://www.hanselman.com/blog/UnlockingWindows8GodModeAUseful
TrickButAlsoMysteriousNonsense.aspx