Archiv für die Kategorie » Windows «
19 | 09 | 2018
PSConf.EU 2019 – Call for Papers ist offen!
Geschrieben von Evgenij um 9:46 Uhr
Ab heute (und bis zum 09.12.2018) können Vorträge für die PowerShell Konferenz 2019 in Hannover eingereicht werden: HIER.
Also los, Community – reicht eure Themen ein, Hannover wartet!
06 | 09 | 2018
CIM Lingen 2018 – Folien und Code-Snippets zu meinem Vortrag
Geschrieben von Evgenij um 16:35 Uhr
Am 01.09.2018 durfte ich auf der diesjährigen CIM Lingen einen Vortrag zum Thema „Running Scripts in the Enterprise“ halten. Ein Thema freilich für strategische Beratungen und lange Refactoring-Projekte, das ich versucht habe, in 45 Minuten zu pressen.
Dennoch konnte ich es mir nicht nehmen lassen, zwei Live Demos einzubauen, und da diese nicht in den Folien waren, poste ich die Code Snippets für Windows und Linux ebenfalls hier. Enjoy!
Demo 1: Konfiguration zu Beginn des Skriptes lesen
Sowohl in der Test- als auch in der Produktionsumgebung ist ein Webserver vorhanden, der auf den Namen https://simpleconfig.it-pro-berlin.de hört (da DNS in Test und in Prod aber voneinander unabhängig ist, löst sich dieser Name zu unterschiedlichen Maschinen auf). Dieser Server stellt die Datei config.xml mit dem folgenden Inhalt zur Verfügung:
<scriptconfig> <runglobal>true</runglobal> <sql dbserver="ciminfra.cim.it-pro-berlin.de" dbname="ScriptsDB" dbuser="confread" dbpasswd="confread">Production SQL Database</sql> </scriptconfig>
Die Aufgabe lautet, den Wert von „runglobal“ auszuwerten und, falls er auf „true“ steht, mit den in der nächsten Zeile enthaltenen Verbindungsdaten zu einem SQL Server zu verbinden und aus der Tabelle „SETTINGS“ ddie Einstellung „ENVIRONMENT“ auszulesen. Die Tabelle enthält zwei Spalten: „settingname“ und „settingvalue“.
Hier ist die Lösung in PowerShell. Dieser Code funktioniert unverändert in Windows PS, PSCore auf Windows und PSCore auf Linux.
function Get-CIMConfig { $config_url = "https://simpleconfig.it-pro-berlin.de/config.xml" $res = $null try { $http_response = Invoke-WebRequest -Uri $config_url -TimeoutSec 10 if ($http_response.StatusCode -eq 200) { $config = ($http_response.content) if ($config.scriptconfig.runglobal -eq "true") { $res = New-Object PSObject -Property @{ "dbserver" = $config.scriptconfig.sql.dbserver "dbname" = $config.scriptconfig.sql.dbname "dbuser" = $config.scriptconfig.sql.dbuser "dbpasswd" = $config.scriptconfig.sql.dbpasswd } } } } catch {} $res } #Jedes Skript beginnt mit $cc = Get-CIMConfig if ($cc) { Write-Host "Ausführung gestattet..." $dbconnstr = "Server=$($cc.dbserver);Database=$($cc.dbname);uid=$($cc.dbuser);pwd=$($cc.dbpasswd)" $dbconn = New-Object System.Data.SqlClient.SqlConnection $dbconn.ConnectionString = $dbconnstr $dbconn.Open() | Out-Null $dbcmd = New-Object System.Data.SqlClient.SqlCommand $dbcmd.Connection = $dbconn $dbcmd.CommandText = "SELECT settingvalue FROM SETTINGS WHERE settingname='ENVIRONMENT'" $dbres = $dbcmd.ExecuteReader() $dbtable = New-Object System.Data.DataTable $dbtable.Load($dbres) Write-Host ("Aktuelle Umgebung: {0}" -f $dbtable.Rows[0]['settingvalue']) }
In Produktion würde man natürlich noch ein wenig mehr Überprüfung und Logging einbauen, aber das ist der wesentliche Teil. Dieser Code benötigt keine externen Module oder Bibliotheken.
In VBS ist der Code etwas sperriger, macht aber was er soll und liefert das gewünschte Ergebnis:
strConfigURL = "https://simpleconfig.it-pro-berlin.de/config.xml" Set wshShell = CreateObject("WScript.Shell") strConfigLocal = wshShell.ExpandEnvironmentStrings("%TEMP%") + "\config.xml" wshShell.Run("cmd.exe /C del /q " + strConfigLocal) Set objHTTP = CreateObject("WinHttp.WinHttpRequest.5.1") objHTTP.Open "GET", strConfigURL, False objHTTP.Send If objHTTP.Status = 200 Then Dim objStream Set objStream = CreateObject("ADODB.Stream") With objStream .Type = 1 'adTypeBinary .Open .Write objHTTP.ResponseBody .SaveToFile strConfigLocal .Close End With Set objStream = Nothing End If Set xmlDoc = CreateObject("Microsoft.XMLDOM") xmlDoc.Async = "False" xmlDoc.Load(strConfigLocal) Set colNodes = xmlDoc.SelectNodes("//scriptconfig/runglobal") For Each objNode in colNodes runglobal = objNode.Text Next If runglobal = "true" Then Set colNodes = xmlDoc.SelectNodes("//scriptconfig/sql") For Each objNode in colNodes dbserver = objNode.Attributes.GetNamedItem("dbserver").Text dbname = objNode.Attributes.GetNamedItem("dbname").Text dbuser = objNode.Attributes.GetNamedItem("dbuser").Text dbpasswd = objNode.Attributes.GetNamedItem("dbpasswd").Text Next strDBConnStr = "Provider=SQLOLEDB;Data Source=" & dbserver & ";Initial Catalog=" & dbname & ";User ID=" & dbuser & ";Password=" & dbpasswd End If 'WScript.Echo(strDBConnStr) Set objDBConn = CreateObject("ADODB.Connection") objDBConn.Open(strDBConnStr) Set objRS = CreateObject("ADODB.Recordset") objRS.Open "SELECT settingvalue FROM SETTINGS WHERE settingname='ENVIRONMENT'", objDBConn, 3, 3 objRS.MoveFirst WScript.Echo("Aktuelle Umgebung: " & objRS.Fields.Item("settingvalue")) objRS.Close() objDBConn.Close()
Die Shell auf Linux (geht in POSIX und in BASH) braucht zwei externe Pakete, XMLLINT und FreeTDS, danach funktioniert es mit
#!/bin/sh wget -q "https://simpleconfig.it-pro-berlin.de/config.xml" -O ~/config.xml runglobal=$(xmllint --xpath "//scriptconfig/runglobal/text()" ~/config.xml) if [ $runglobal = true ] then echo "Ausführung gestattet..." dbserver=$(xmllint --xpath "string(//scriptconfig/sql/@dbserver)" ~/config.xml) dbname=$(xmllint --xpath "string(//scriptconfig/sql/@dbname)" ~/config.xml) dbuser=$(xmllint --xpath "string(//scriptconfig/sql/@dbuser)" ~/config.xml) dbpasswd=$(xmllint --xpath "string(//scriptconfig/sql/@dbpasswd)" ~/config.xml) env=$(bsqldb -U $dbuser -P $dbpasswd -S $dbserver -D $dbname -i sico1.sql 2>&-) echo "Umgebung: " $env fi
Die Datei sico1.sql könnte man natürlich dynamisch aus dem Skript generieren, für den Zweck der Demo ist sie aber statisch und hat den folgenden wenig überraschenden Inhalt:
SELECT settingvalue FROM SETTINGS WHERE settingname='ENVIRONMENT'
An der CMD-Shell schaut es natürlich etwas mau aus, dort hat man sich in der Vergangenheit ja immer wieder mit einer selbstgeschriebenen EXE beholfen. Man kann natürlich auch das o.g. VBS-Skript zu Begimn des CMD-Batchscripts bemühen.
Demo 2: Auf einen SYSLOG-Server schreiben
Einträge auf einem SYSLOG-Server erzeugen, das schaffen Skriptsprachen auch. PowerShell (auch Core) nutzt die System.Net-Klassen:
$syslog_server = 'ciminfra.cim.it-pro-berlin.de' $Log_Message = 'PowerShell:TEST' #0=EMERG 1=Alert 2=CRIT 3=ERR 4=WARNING 5=NOTICE 6=INFO 7=DEBUG $Log_Severity = '1' #(16-23)=LOCAL0-LOCAL7 $Log_Facility = '22' # Calculate the priority $Log_Prio = ([int]$Log_Facility * 8) + [int]$Log_Severity $Sender = $env:COMPUTERNAME #Time format the SW syslog understands $TS = Get-Date -Format "MMM dd HH:mm:ss" # Assemble the full syslog formatted message $FullSyslogMessage = "<{0}>{1} {2} {3}" -f $Log_Prio, $TS, $Sender, $Log_Message $FullSyslogMessage # create an ASCII Encoding object $Encoding = [System.Text.Encoding]::ASCII # Convert into byte array representation $ByteSyslogMessage = $Encoding.GetBytes($FullSyslogMessage) $UDPCLient = New-Object System.Net.Sockets.UdpClient $UDPCLient.Connect($syslog_server, 514) $UDPCLient.Send($ByteSyslogMessage, $ByteSyslogMessage.Length) $UDPCLient.Close()
VBS und CMD-Shell müssen hier, wenig überraschend, ohne externe Unterstützung passen, die BASH-Shell hingegen ist der absolute Champion (das gilt aber nicht für die POSIX-Shell):
#!/bin/bash msg="Linux_bash:TESTLOG Definitive" facility=21 #local5 severity=4 #WARN prio=$((8 * $facility + $severity)) syslogserver="ciminfra.cim.it-pro-berlin.de" hname=$(hostname) ts=$(date "+%b %d %H:%M:%S") syslogmsg="<$prio>$ts $hname $msg" echo "$syslogmsg" > /dev/udp/$syslogserver/514
Folien von der CIM
02 | 09 | 2018
CIM Lingen 2018 – das war schön
Geschrieben von Evgenij um 8:17 Uhr
Gestern hatte ich die Ehre, auf der CIM Lingen 2018 zu „Running Scripts in the Enterprise“ (was sonst?) zu sprechen. Bis dato hatte ich die CIM gar nicht auf dem Schirm gehabt, aber die Emsländer Community-Konferenz hat sich als eine ganz tolle Veranstaltung entpuppt. Trotz einer ordentlichen Größe von 300 Teilnehmern ist die Atmosphäre eines User Group-Treffens unverkennbar vorhanden. An dieser Stelle nochmals vielen Dank an das Orga-Team und natürlich an die Sponsoren, zu denen sowohl mein jetziger als auch mein ehemaliger Arbeitgeber gehören.
Ich habe einige tolle Menschen kennengelernt und einige bisher nur aus dem Online-Geschehen bekannte endlich in Person getroffen. Etwas traurig war es zu sehen, dass langjährigen MVPs und absoluten Grundsteinen der deutschen Microsoft-Community die Auszeichnung mit der Begründung „too little cloud content“ entzogen wurde. Schämt euch, Microsoft! Ihr werdet schon sehen, was ihr davon habt.
Nächstes Jahr soll die (nunmehr 15.) CIM an zwei Tagen stattfinden – 13. + 14.09.2019 (save the date!) und über acht Tracks gehen. Es sind 50 Sessions angekündigt, es ergeben sich also rechnerisch, abzüglich der Opening und der Closing Keynote, drei Slots pro Tag in jedem Track. Somit hätte jeder Slot voraussichtlich eine Länge, die einen deutlich tieferen Einstieg in das jeweilige Thema erlaubt. Drückt mir die Daumen – das wäre genau mein Ding, denn diesmal bin ich etwas aus der Zeit geraten und musste am Ende des 45-minütigen Slots ganz schön hetzen.
Also: auf zur nächsten CIM: #cimlingen #communityrocks
16 | 07 | 2018
PowerShell Quirks: Beware of collections, die N+1.
Geschrieben von Evgenij um 23:31 Uhr
Ich habe ja schon des öfteren über Eigenarten von Sammlungen aller Art in PowerShell berichtet. Heute ein Beispiel aus der Active Directory-Administration.
Nehmen wir einfach mal an, wir haben ein mehrwertiges Attribut und wollen zu diesem einen zusätzlichen Wert hinzufügen. Für diese Beispiel nehme ich msExchExtensionCustomAttribute1, da kann man nichts kaputt machen.
Set-ADUser john.doe -Replace @{msExchExtensionCustomAttribute1=@("A","B","C")} $user = Get-ADUser john.doe -Properties msExchExtensionCustomAttribute1 $a1 = $user.msExchExtensionCustomAttribute1 Write-Host "Unser Attribut msExchExtensionCustomAttribute1:" $a1.GetType() $a1
Nun wollen wir zu $a1 ein viertes Element hinzufügen. IntelliSense in ISE bietet folgendes an:
Auch wenn’s bei nativen PowerShell-Arrays nicht funktioniert, ist Add doch vielversprechend. Probieren wir’s aus:
$a1.Add("D") Write-Host "`r`nNach dem Add:" $a1.GetType() $a1
liefert
Sieht doch super aus, richtig? Der Typ ist derselbe, alle vier Elemente sind wie erwartet da. Nun bleibt also die neue Sammlung zurück in das Attribut zu schreiben und das Ergebnis zu überprüfen:
Set-ADUser john.doe -Replace @{msExchExtensionCustomAttribute1=$a1} Get-ADUser john.doe -Properties msExchExtensionCustomAttribute1
Doch das Ergebnis ist leider nicht ganz das, was wir erwartet haben:
Das soeben beschriebene Attribut ist leer. Hmmm.
Machen wir das gleiche Spiel und nehmen statt der Methode .Add das PowerShell-eigene Anfügen:
$a1 += "D"
so ist das Ergebnis wie erwartet:
Der alles entscheidende Unterschied ist anscheinend, dass die Operation += die ADPropertyValueCollection in ein System.Array konvertiert. Und dieses wird offenbar von Set-ADUser korrekt interpretiert, sein nativer Datentyp hingegen nicht!
Happy updating!
15 | 05 | 2018
Die Windows Server User Group Berlin trifft sich am 24. Mai
Geschrieben von Evgenij um 10:22 Uhr
Das nächste Treffen (Q2/2018) der WSUG-B findet am Donnerstag, dem 24.05.2018 bei der COMPAREX AG in Berlin-Adlershof. Details und Anmeldung über Meetup.com: https://www.meetup.com/de-DE/Windows-Server-User-Group-Berlin/events/250092212/
06 | 05 | 2018
Besser spät als nie: Windows Command Reference als PDF
Geschrieben von Evgenij um 14:33 Uhr
Haben wir uns das nicht alle schon mal gewünscht – eine ordneltiche Hilfe zu den zahlreichen Kommandozeilen-Befehlen? Jetzt, wo man schon dachte, nun ist PowerShell da und es kommt keine CMD-Doku mehr, hat Microsoft sich einen Ruck gegeben und die folgende coole PDF rausgebracht: https://www.microsoft.com/en-us/download/details.aspx?id=56846
Happy commandlining!
16 | 01 | 2018
Windows Server User Group Berlin: Das erste Treffen des Jahres am 25.01.2018
Geschrieben von Evgenij um 19:27 Uhr
Das erste Treffen der Windows Server User Group Berlin wird am Donnerstag, dem 25.01.2018 um 18 Uhr bei der Jaemacom GmbH in der Friedenstr. 91 stattfinden. Auf dem Programm stehen Vorträge zu künstlicher Intelligenz und zu Security in Windows-Landschaften.
Für das leibliche Wohl wird auch gesorgt sein.
Um die Organisation zu unterstützen, bitten wir um Anmeldung unter https://winsvr.events/event.php?vnr=11-106 .
Bis bald bei der WSUGB!
09 | 01 | 2018
PST über LAN ist ja doch supported ;-)
Geschrieben von Evgenij um 21:50 Uhr
…zumindest so ein bißchen, nur in einem Szenario und nur in Bezug auf die Funktion, nicht auf die Performance. Das ist einer aus der Rubrik „wieder was gelernt“. Enjoy: https://support.microsoft.com/en-us/help/297019/limits-to-using-personal-folders–pst-files-over-lan-and-wan-links
P-L-E-A-S-E don’t do this at homework! (hier ist, warum: https://blogs.technet.microsoft.com/askperf/2007/01/21/network-stored-pst-files-dont-do-it/) Wenn jemand Hilfe bei der Abschaffung von PSTs braucht, fragt mich 😉
09 | 01 | 2018
Die Windows Server User Group Berlin trifft sich am 25.01.2018
Geschrieben von Evgenij um 20:30 Uhr
Als Host und Sponsor beherbergt uns diesmal die Jaemacom GmbH.
Agenda und Anmeldung: [ KLICK ]
29 | 11 | 2017
Microsoft VDI-Lizenzierung – wieder was gelernt…
Geschrieben von Evgenij um 19:53 Uhr
Hier ein Quickie, das habe ich offenbar bisher übersehen und bin heute zufällig darauf gestoßen: In https://blogs.technet.microsoft.com/volume-licensing/2014/03/10/licensing-how-to-when-do-i-need-a-client-access-license-cal/ findet sich der folgende Passus:
RDS CALs are required only when accessing the Windows Server GUI, or if any of the RDS components listed are used (e.g. Remote Desktop Web Access, Remote Desktop Gateway, Remote Desktop Connection Broker, Remote Desktop Session Host, or the Remote Desktop Virtualization Host.) If you are using a third party VDI solution, and it does not use any of the RDS components, then RDS CALs are not required.
Übersetzt bedeutet das für den Fall einer reinen VDI, d.h. mit 100% Client-Betriebssystemen als Workern:
- Ich baue eine Citrix XenDesktop- oder VMware View-VDI: Die Worker brauchen SA und, je nach Beschaffenheit der Benutzer-Endgeräte, VDA. Das ist blöd genug, aber erst mal nicht zu ändern.
- Ich baue eine VDI mit Microsoft-Mitteln: Man braucht alles oben Genannte und zusätzlich noch RDS CALs für die ganze Chose!
Wo ist denn hier die Logik? Und da soll mir noch jemand erzählen, Microsoft würde eigene Produkte auf Kosten des Wettbewerbs pushen…
Happy Year of Desktop Virtualization (as proclaimed by Gartner every year since 2007 for the following year so we’re apparently having a 10th coming up…)