Archiv für die Kategorie » PowerShell «

17 | 08 | 2019

Ich werde auf der CIM Lingen 2019 sprechen

Geschrieben von um 15:49 Uhr

Nach langem Warten steht die Agenda der diesjährigen CIM Lingen für den Community Day am 14.09.2019 nun fest – und ich bin dabei. Es scheint noch Tickets zu geben – meldet euch an, der Besuch ist kostenlos, aber auf gar keinen Fall umsonst!

Mich findet ihr am Samstag um 10:45 im Dev-Track oder am Freitagnachmittag irgendwo auf dem Business Day.

Bis Mitte September in Lingen!

Tags » , , , , «

+

27 | 07 | 2019

PowerShell Gallery ansprechen hinter einem Proxy

Geschrieben von um 11:14 Uhr

Es ist kein wirklich neues Ergebnis, aber ich möchte es zur Erinnerung hier festhalten.

Wer sich in der Situation wiederfindet, hinter einem authentifizierungspflichtigen Proxy PowerShell-Module aus der Gallery (oder anderen externen PowerShellGet-Repositories) finden und installieren zu müssen, kann leider nicht darauf bauen, dass man den entsprechenden Cmdlets vermitteln kann, dass ein Proxy im Weg ist.

Stattdessen muss man die gesamte Sitzung zur Nutzung des Proxy befähigen. Das geht mit drei Zeilen Code, die man – je nachdem, wie das Verhältnis zwischen Komfort und ParanoiaSicherheitsbewuisstsein ausgeprägt ist – entweder als Skript aufruft oder in sein PowerShell-Profil schreibt. An Letzteres kommt man mit

Start-Process notepad.exe -ArgumentList $Profile.CurrentUserCurrentHost

oder, falls man VSCode im Standardpfad installiert hat, mit

Start-Process "C:\Program Files\Microsoft VS Code\Code.exe" -ArgumentList $Profile.CurrentUserCurrentHost

Das Profil ist übrigens getrennt für PowerShell.exe und PowerShell_ISE.exe – die Variable $Profile wird unterschiedliche Werte in den beiden hostspezifischen Eigenschaften „CurrentUserCurrentHost“ und „AllUsersCurrentHost“ haben.

Folgender Code gehört also ins Profil:

[system.net.webrequest]::defaultwebproxy = new-object system.net.webproxy('http://proxy.domain.net:3128')
[system.net.webrequest]::defaultwebproxy.BypassProxyOnLocal = $true

Je nachdem, ob der Proxy die PassThrough-Authentifizierung der Windowssitzung nutzt oder eine explizite Authentifizierung verlangt, muss der Aufruf noch durch

[system.net.webrequest]::defaultwebproxy.credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials

bzw.

[system.net.webrequest]::defaultwebproxy.credentials = New-Object PSCredential('proxyuser',('proxypassword' | ConvertTo-SecureString -AsPlainText -Force)) 

ergänzt werden.
Happy NuGetting!

Tags » , , «

+

27 | 07 | 2019

Ich werde auf dem PSDAY.UK am 28.09. sprechen

Geschrieben von um 10:45 Uhr

Am 28.09.2019 findet in Birmingham der diesjährige PSDAY.UK statt. Ich habe die Ehre, zu den ausgewählten Speakern zu gehören und den Saal für Richard Siddaway vorzuwärmen.

Übrigens: Es gibt noch Tickets, sowohl PSDAY-Tickets als auch Flugtickets 😉

Tags » , , , , «

+

02 | 04 | 2019

AD User mit ausgeschalteter Vererbung der Rechte finden mit PowerShell – revisited

Geschrieben von um 15:15 Uhr

Vor sieben Jahren habe ich mal hier beschrieben, wie man schnell alle User mit ausgeschalteter Rechtevererbung findet. Damals war das Quest AD-Modul (aus ActiveRoles) das Mittel der Wahl, welches mittlerweile nicht mehr (kostenlos) verfügbar ist. Hier ein Code Snippet, um das gleiche mit dem nativen AD-Modul des Windows Servers zu erreichen:

$users = Get-ADUser -LDAPFilter "(mail=*)"
foreach ($user in $users) {
    $adsu = [ADSI]"LDAP://$($user.DistinguishedName)"
    if ($adsu.PSBase.objectSecurity.AreAccessRulesProtected) {
        $user.DistinguishedName
    }
}

Das Zurücksetzen der Vererbung ist etwas komplizierter als bei Quest und benutzt den AD-Provider aus dem Modul:

$users = Get-ADUser -LDAPFilter "(mail=*)"
foreach ($user in $users) {
    $adsu = [ADSI]"LDAP://$($user.DistinguishedName)"
    if ($adsu.PSBase.objectSecurity.AreAccessRulesProtected) {
        $acl = Get-ACL "AD:\$($user.DistinguishedName)"
        $acl.SetAccessRuleProtection($false,$false)
        Set-ACL -ACLObject $acl -Path "AD:\$($user.DistinguishedName)"
    }
}

Man sollte im Hinterkopf behalten, dass bei Mitgliedern in Admin-Gruppen diese Änderung durch AD wieder zurückgerollt werden wird (Stichwort AdminSDHolder), und bei produktivem Einsatz vielleicht eine Prüfung einbauen.

Happy migrating!

Tags » , , , , , «

+

09 | 03 | 2019

Windows Server User Group Berlin: Die Agenda für 21.03. steht fest

Geschrieben von um 11:43 Uhr

Die Agenda des anstehenden User Group-Treffens am 21. März steht nun fest. Alle Details und Anmeldung wie immer auf Meetup. Es sind noch Plätze frei!

Tags » , , , , , , «

+

23 | 02 | 2019

Windows Server User Group Berlin trifft sich am 21. März

Geschrieben von um 13:27 Uhr

Das erste Treffen des Jahres 2019 findet am 21. März bei der COMPAREX AG in Berlin-Adlershof statt. Agenda steht noch nicht fest und wird in den nächsten Tagen aktualisiert. Vorträge, kurz oder lang, können noch eingereicht werden.
Alle Details und Anmeldung: https://www.meetup.com/de-DE/Windows-Server-User-Group-Berlin/events/259153636/

Tags » , , , , «

+

22 | 12 | 2018

Ich werde auf der PSConf.EU 2019 sprechen

Geschrieben von um 22:15 Uhr

Als ob die Vorweihnachtszeit nicht aufregend genug wäre: Gerade wurde die Speaker-Liste der europäischen PowerShell-Konferenz 2019 (http://www.psconf.eu/) auf Twitter veröffentlicht, und ich bin dabei!

Tags » , , «

+

29 | 11 | 2018

PSConf.EU 2019 – Registrierung ist eröffnet!

Geschrieben von um 9:44 Uhr

Das Traditions-Event geht in die vierte Runde: Hannover, im HCC, 4.-7. Juni 2019, alle Details und Anmeldung unter https://www.psconf.eu/

Die Registrierung ist ab sofort offen, also: schnell anmelden und ein halbes Jahr Vorfreude geniessen!

Tags » , , «

+

19 | 09 | 2018

PSConf.EU 2019 – Call for Papers ist offen!

Geschrieben von 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!

Tags » , , , , «

+

10 | 09 | 2018

PowerShell Quirks: Values aus der Pipeline, Object Edition

Geschrieben von um 17:51 Uhr

Heute gab es mal wieder eine interessante Frage im TechNet-Forum. Das wollte ich mal näher untersuchen. Es ging darum, dass beim Pipen eines Objektes nach New-Item der Inhalt des erstellten Items das gesamte Objekt, aufgedröselt als Hashtable, enthielt. Im Thread war es eine Datei, aber mit dem Registry-Provider funktionierte es genau so. Das interessante am Value-Parameter ist, dass er Argumente nicht nur nach Namen, sondern auch nach dem Wert bindet:

Doch ist es nur eine Eigenart von New-Item oder ist das Verhalten generell so? Schreiben wir mal eine kleine Funktion, die ihre Argumente, falls sie aus der Pipeline angeflogen kommen, ganz regulär nach Namen bindet:

function Get-MyArgs {
    [CmdletBinding()]
    Param(
        [Parameter(ValueFromPipelineByPropertyName=$true)][string]$MyInput,
        [Parameter(ValueFromPipelineByPropertyName=$true)][string]$MyOtherParm
    )
    Write-Host "Value of MyOtherParm:"
    $MyOtherParm
    Write-Host "Value of MyInput:"
    $MyInput
}

Wenn wir der Funktion jetzt ein Objekt verfüttern, das die gewünschten Properties enthält, werden sie auch ordnungsgemäß gebunden:

$x = New-Object PSCustomObject -Property @{
    MyInput="MyInputValue";
    MyOtherParm="MyOtherParmValue";
    ForeignParm="ShouldNotSeeMe"
}
$x | Get-MyArgs

liefert

Value of MyOtherParm:
MyOtherParmValue
Value of MyInput:
MyInputValue

Akzeptieren wir nur die gleichen Parameter, aber nach dem Wert, wartet eine kleine Überraschung auf uns:

function Get-MyArgs {
    [CmdletBinding()]
    Param(
        [Parameter(ValueFromPipeline=$true)][string]$MyInput,
        [Parameter(ValueFromPipeline=$true)][string]$MyOtherParm
    )
    Write-Host "Value of MyOtherParm:"
    $MyOtherParm
    Write-Host "Value of MyInput:"
    $MyInput
}
$x = New-Object PSCustomObject -Property @{
    MyInput="MyInputValue";
    MyOtherParm="MyOtherParmValue";
    ForeignParm="ShouldNotSeeMe"
}
$x | Get-MyArgs

liefert uns

Value of MyOtherParm:
@{MyInput=MyInputValue; MyOtherParm=MyOtherParmValue; ForeignParm=ShouldNotSeeMe}
Value of MyInput:
@{MyInput=MyInputValue; MyOtherParm=MyOtherParmValue; ForeignParm=ShouldNotSeeMe}

Und jetzt kommt der Quirk:

Was passiert aber, wenn wir, wie bei Value in New-Item, beide Bindungen zulassen? Also

function Get-MyArgs {
    [CmdletBinding()]
    Param(
        [Parameter(ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)][string]$MyInput,
        [Parameter(ValueFromPipelineByPropertyName=$true,ValueFromPipeline=$true)][string]$MyOtherParm
    )
    Write-Host "Value of MyOtherParm:"
    $MyOtherParm
    Write-Host "Value of MyInput:"
    $MyInput
}
$x = New-Object PSCustomObject -Property @{
    MyInput="MyInputValue";
    MyOtherParm="MyOtherParmValue";
    ForeignParm="ShouldNotSeeMe"
}
$x | Get-MyArgs

Anders als bei New-Item, erhalten wir nur die String-Werte der beiden benannten Parameter!
Eine Untersuchung mit

Trace-Command -Name ParameterBinding -Expression {$x | Get-MyArgs} -PSHost

fördert die folgenden Schritte zu Tage:

BIND PIPELINE object to parameters: [Get-MyArgs]
    PIPELINE object TYPE = [System.Management.Automation.PSCustomObject]
    RESTORING pipeline parameter's original values
    Parameter [MyOtherParm] PIPELINE INPUT ValueFromPipeline NO COERCION
    BIND arg [@{MyInput=MyInputValue; MyOtherParm=MyOtherParmValue; ForeignParm=ShouldNotSeeMe}] to parameter [MyOtherParm]
        Executing DATA GENERATION metadata: [System.Management.Automation.ArgumentTypeConverterAttribute]
            result returned from DATA GENERATION: @{MyInput=MyInputValue; MyOtherParm=MyOtherParmValue; ForeignParm=ShouldNotSeeMe}
        BIND arg [@{MyInput=MyInputValue; MyOtherParm=MyOtherParmValue; ForeignParm=ShouldNotSeeMe}] to param [MyOtherParm] SKIPPED
    Parameter [MyInput] PIPELINE INPUT ValueFromPipeline NO COERCION
    BIND arg [@{MyInput=MyInputValue; MyOtherParm=MyOtherParmValue; ForeignParm=ShouldNotSeeMe}] to parameter [MyInput]
        Executing DATA GENERATION metadata: [System.Management.Automation.ArgumentTypeConverterAttribute]
            result returned from DATA GENERATION: @{MyInput=MyInputValue; MyOtherParm=MyOtherParmValue; ForeignParm=ShouldNotSeeMe}
        BIND arg [@{MyInput=MyInputValue; MyOtherParm=MyOtherParmValue; ForeignParm=ShouldNotSeeMe}] to param [MyInput] SKIPPED
    Parameter [MyOtherParm] PIPELINE INPUT ValueFromPipelineByPropertyName NO COERCION
    BIND arg [MyOtherParmValue] to parameter [MyOtherParm]
        Executing DATA GENERATION metadata: [System.Management.Automation.ArgumentTypeConverterAttribute]
            result returned from DATA GENERATION: MyOtherParmValue
        BIND arg [MyOtherParmValue] to param [MyOtherParm] SUCCESSFUL
    Parameter [MyInput] PIPELINE INPUT ValueFromPipelineByPropertyName NO COERCION
    BIND arg [MyInputValue] to parameter [MyInput]
        Executing DATA GENERATION metadata: [System.Management.Automation.ArgumentTypeConverterAttribute]
            result returned from DATA GENERATION: MyInputValue
        BIND arg [MyInputValue] to param [MyInput] SUCCESSFUL
MANDATORY PARAMETER CHECK on cmdlet [Get-MyArgs]

Bei New-Item ist das Value-Argument allerdings kein [string], sondern ein [object[]] (danke an Martin Binder für den Hinweis, dass dieser Test noch aussteht!). Ändert man das im obigen Beispiel, dann ist das Verhalten so wie bei New-Item auch, und zwar unabhängig davon, ob ein einzelnes [object] oder ein Array davon erwartet wird – es wird in beiden Fällen das ganze Objekt gebunden, sobald ValueFromPipeline=$true auftaucht.
Happy argument-passing!

Tags » , , , «

+