September 13

NTFS Berechtigungen anhand Ordnername setzen

Neuer Fileserver, neue Homedrives… Diese liegen alle in einem Verzeichnis und haben als Ordnername den Username. Auf dem Ordner muss der User berechtigt werden (NTFS ACL). Dies kann mit folgendem Powershell Script schnell und einfach erledigt werden:

Download des Script

 


#############################################################################
# Script: changePermissions.ps1
# Author: Internet & Luis Goncalves & Rui Duarte & Manuel Kuss
# Date: 13/09/2017
# Keywords:
# Comments: Fixed Version for Powershell v3
# Pre-Requisites: Full Control over destination folder.
#
# DISCLAIMER
# ==========
# THIS CODE IS MADE AVAILABLE AS IS, WITHOUT WARRANTY OF ANY KIND. THE ENTIRE
# RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS CODE REMAINS WITH THE USER.
#############################################################################
#
# Where is the root of the home drives?
$homeDrivesDir="F:\DATA"
# Report only? ($false = fix problems)
$reportMode = $false
# Print all valid directories?
$verbose = $true
# What domain are your users in?
$domainName = "DOMAINNAME.LOCAL"
#
# ACL Options:
# Grant the user full control (FullControl, Modify, ...)
$accessLevel = "Modify"
# Should permissions be inherited from above? (ContainerInherit, ObjectInherit or None)
$inheritanceFlags = "ContainerInherit, ObjectInherit"
# Should permissions propagate to below?
$propagationFlags = "None"
# Is this an Allow/Deny entry?
$accessControlType = "Allow"
#############################################################################
# Save the current working directory before we change it (purely for convenience)
pushd .
# Change to the location of the home drives
set-location $homeDrivesDir
# Warn the user if we will be fixing or just reporting on problems
write-host ""
if ($reportMode) {
Write-Host "Report mode is on. Not fixing problems"
} else {
Write-Host "Report mode is off. Will fix problems"
}
write-host ""
# Initialise a few counter variables. Only useful for multiple executions from the same session
$goodPermissions = $unfixablePermissions = $fixedPermissions = $badPermissions = 0
$failedFolders = @()
# For every folder in the $homeDrivesDir folder
foreach($homeFolder in (Get-ChildItem $homeDrivesDir | Where {$_.psIsContainer -eq $true})) {
# dump the current ACL in a variable
$acl= (Get-Item $homeFolder).GetAccessControl("Access")
# create a permission mask in the form of DOMAIN\Username where Username=foldername
# (adjust as necessary if your home folders are not exactly your usernames)
$compareString = "*" + $domainName + "\" + $homeFolder.Name + " Allow FullControl*"
# if the permission mask is in the ACL
if ($Acl.AccessToString -like $compareString) {
# everything's good, increment the counter and move on.
if ($verbose) {Write-Host "Permissions are valid for" $homeFolder.Name -backgroundcolor green -foregroundcolor white}
$goodPermissions += 1
} else {
# Permissions are invalid, either fix or report
# increment the number of permissions needing repair
$badPermissions += 1
# if we're in report mode
if ($reportMode -eq $true) {
# reportmode is on, don't do anything
Write-Host "Permissions not valid for" $homeFolder.Name -backgroundcolor red -foregroundcolor white
} else {
# reportmode is off, fix the permissions
Write-Host "Setting permissions for" $homeFolder.Name -foregroundcolor white -backgroundcolor red
# Add the user in format DOMAIN\Username
$username = $domainName + "\" + $homeFolder.Name
try {
# Create the Access Rule
$accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($username,$accessLevel,$inheritanceFlags,$propagationFlags,$accessControlType)
# Attempt to apply the access rule to the ACL
$Acl.SetAccessRule($accessRule)
Set-Acl -Path $homeFolder -AclObject $Acl
# if it hasn't errored out by now, increment the counter
$fixedPermissions += 1
} catch {
# It failed!
# Increment the fail count
$unfixablePermissions += 1
# and add the folder to the list of failed folders
$failedFolders += $homeFolder
}
} #/if
} #/if
} #/foreach
# Print out a summary
Write-Host ""
Write-Host $goodPermissions "valid permissions"
Write-Host $badPermissions "permissions needing repair"
if ($reportMode -eq $false) {Write-Host $fixedPermissions "permissions fixed"}
if ($unfixablePermissions -gt 0) {
Write-Host $unfixablePermissions "ACLs could not be repaired."
foreach ($folder in $failedFolders) {Write-Host " -" $folder}
}
# Cleanup
popd

 

Die Powershell v2 Version ist ursprünglich von hier.

März 20

Windows Server Patching mit PoshPAIG

Jeden Monat das selbe… Es gibt neue Windows Server Updates und diese sollten zeitnah auf allen Servern eingespielt werden. Mit WSUS und Gruppenrichtlinien kann man das vollständig automatisieren was aber nicht in jeder Umgebung gewünscht ist.

Sich auf jeden Server per RDP aufschalten und die Updates von Hand zu installieren ist jedoch auch müssig.

Unterstützen kann hier das PowerShell Patch/Audit Utility (PoshPAIG) von Boe Prox:

Mit PoshPAIG kann man eine Liste von Servern automatisiert auf folgende Optionen hin abprüfen:

  • Audit Patches
  • Install Patches
  • Check Pending Reboot
  • Ping Sweep
  • Services Check
  • Reboot Systems

Zusätzlich kann man sich noch eine handvoll CSV Reports erstellen lassen.

 

Alles in allem eine feine Sache für alle, die den Patchvorgang nicht vollständig durch automatisieren möchten.

April 7

VDI Maintenance Mode Switcher Powershell Script

Problem: VDI Maschinen in unserer Farm werden bei Inaktivität heruntergefahren und nur bei Bedarf gestartet. Dadurch kann es vereinzelt Maschinen geben, die nur sehr selten Online sind. Daher fehlen hier aktuelle Polices, Patches und Softwarepakete.

Lösung: Ich habe ein PowerShell Script geschrieben, welches über den Aufgabenplaner am Wochenende ausgeführt werden kann. Das Script aktiviert/deaktiviert den Maintenance Mode und (neu-)stratet die entsprechenden Maschinen.

Mal sehen ob sich das bewährt… :-)
Dies ist so nebenbei auch mein erstes handgeklöppeltes Powershell Script, für Fehler übernehme ich keine Haftung.

 

-> get the script <-

 

VDI_MM_Switcher_v1.4.ps1

<#
.SYNOPSIS
    This script enable or disable Maintenance Mode for Citrix VDI machines.
.DESCRIPTION
    The script read a static text file with hostnames and enable or disable maintance mode for each machine.
    The script will wait 60 seconds after each machine.
    If a target VDI is powered off it will be started automatically, if a target VDI is powered on it will be restarted if not in use.
.PARAMETER MaintenanceMode
    Specifies if the Maintenance Mode should be switched on or off. Options: Enable, Disable.
.PARAMETER HostListFile
    List of target Host names without Domain.
.EXAMPLE
    powershell.exe '.\VDI_MM_Switcher_v1.4.ps1' -MaintenanceMode "Enable" -HostListFile "C:\VDI_MM_Switcher\hosts.txt"
.EXAMPLE
    powershell.exe '.\VDI_MM_Switcher_v1.4.ps1' -MaintenanceMode "Disable" -HostListFile "C:\VDI_MM_Switcher\hosts.txt"
.NOTES
    Change Log
    V1.0 - 05.04.2016 - Manuel Kuss - frist release
    V1.1 - 05.04.2016 - Manuel Kuss - added logging
    V1.3 - 06.04.2016 - Manuel Kuss - added param()
    V1.4 - 07.04.2016 - Manuel Kuss - added SummaryState check
.LINK 
    http://www.nova17.de
#>

param(
    [string]$MaintenanceMode,
    [string]$HostListFile
)

Clear

## Load Addins
Add-PSSnapin Citrix.*

## Syntax Checker
If (($MaintenanceMode -eq "") -or ($HostListFile -eq "")) {
    Write-Host "ERROR MISSING PARAMETER`nSyntax: .\VDI_MM_Switcher_v1.4.ps1 -MaintenanceMode `"Enable/Disable`" -HostListFile `"C:\Path\hosts.txt`"" -ForegroundColor Red
    Exit
} 

## Variables (customize)
$AdminServer = 'hostname.domain.tld'
$ADDomain = 'YOUR-AD-DOMAIN'
## Variables
$HostList = Get-Content $HostListFile
$Logfile = "$HostListFile" + "_$MaintenanceMode" + ".log"

## Output
Write-Host "Executing..." -ForegroundColor Yellow
$starttime = Get-Date -Format G
write "--------------------------------------------------------" | Out-File $Logfile
Write "Script Start Time: $starttime" | Out-File $Logfile -Append
write "--------------------------------------------------------" | Out-File $Logfile -Append

## Enable Maintenance Mode Loop ##
if ($MaintenanceMode -eq 'Enable') 
    {
    foreach ($item in $HostList)
        {
            ## Write DOMAIN\HOSTNAME to $TargetVDI
            $TargetVDI = "$ADDomain" + "\" + "$item"
            
            ## Enable Maintenance Mode
            Write "Enable MaintenanceMode for $TargetVDI" | Out-File $Logfile -Append
            Set-BrokerMachineMaintenanceMode -InputObject $TargetVDI $true -adminaddress $AdminServer

            ## Restart if TargetVDI is not in use
            foreach ($item in Get-BrokerDesktop | Where-Object{($_.MachineName -eq "$TargetVDI") -and ($_.PowerState -eq "On") -and ($_.SummaryState -ne "InUse")} | Select-Object -Property MachineName)
                { New-BrokerHostingPowerAction -MachineName $TargetVDI -Action Restart -adminaddress $AdminServer | Out-File $Logfile -Append }

            ## If TargetVDI is powered off
            foreach ($item in Get-BrokerDesktop | Where-Object{($_.MachineName -eq "$TargetVDI") -and ($_.PowerState -eq "Off")} | Select-Object -Property MachineName)
                { New-BrokerHostingPowerAction -MachineName $TargetVDI -Action TurnOn -adminaddress $AdminServer | Out-File $Logfile -Append }
            
            ## Pause
            Write "--------------------------------------------------------" | Out-File $Logfile -Append
            Start-Sleep 60
        }
    }

## Disable Maintenance Mode Loop ##
if ($MaintenanceMode -eq 'Disable') 
    {
    foreach ($item in $HostList)
        {
            ## Write DOMAIN\HOSTNAME to $TargetVDI
            $TargetVDI = "$ADDomain" + "\" + "$item"
          
            ## Disable MaintenanceMode
            Write "Disable MaintenanceMode for $TargetVDI" | Out-File $Logfile -Append
            Set-BrokerMachineMaintenanceMode -InputObject $TargetVDI $false -adminaddress $AdminServer
            
            ## Restart if TargetVDI is not in use
            foreach ($item in Get-BrokerDesktop | Where-Object{($_.MachineName -eq "$TargetVDI") -and ($_.PowerState -eq "On") -and ($_.SummaryState -ne "InUse")} | Select-Object -Property MachineName)
                { New-BrokerHostingPowerAction -MachineName $TargetVDI -Action Restart -adminaddress $AdminServer | Out-File $Logfile -Append }
                           
            ## Pause
            Write "--------------------------------------------------------" | Out-File $Logfile -Append
            Start-Sleep 60
        }
    }

## Output
$endtime = Get-Date -Format G
Write "Script End Time: $endtime" | Out-File $Logfile -Append
write "--------------------------------------------------------" | Out-File $Logfile -Append
Write-Host "Script Execuded." -ForegroundColor Yellow
Dezember 8

Windows 10 Built-In Apps

Wer die Built-In Apps von Windows 10 (teilweise) deinstallieren möchte, kann dies am einfachsten per PowerShell erledigen. Hier sind die jeweiligen Befehle:

3D Builder: Get-AppxPackage *3dbuilder* | Remove-AppxPackage
Alarms and Clock: Get-AppxPackage *windowsalarms* | Remove-AppxPackage
Calculator: Get-AppxPackage *windowscalculator* | Remove-AppxPackage
Calendar and Mail: Get-AppxPackage *windowscommunicationsapps* | Remove-AppxPackage
Camera: Get-AppxPackage *windowscamera* | Remove-AppxPackage
Get Office: Get-AppxPackage *officehub* | Remove-AppxPackage
Get Skype: Get-AppxPackage *skypeapp* | Remove-AppxPackage
Get Started: Get-AppxPackage *getstarted* | Remove-AppxPackage
Groove Music: Get-AppxPackage *zunemusic* | Remove-AppxPackage
Maps: Get-AppxPackage *windowsmaps* | Remove-AppxPackage
Microsoft Solitaire Collection: Get-AppxPackage *solitairecollection* | Remove-AppxPackage
Money: Get-AppxPackage *bingfinance* | Remove-AppxPackage
Movies & TV: Get-AppxPackage *zunevideo* | Remove-AppxPackage
News: Get-AppxPackage *bingnews* | Remove-AppxPackage
OneNote: Get-AppxPackage *onenote* | Remove-AppxPackage
People: Get-AppxPackage *people* | Remove-AppxPackage
Phone Companion: Get-AppxPackage *windowsphone* | Remove-AppxPackage
Photos: Get-AppxPackage *photos* | Remove-AppxPackage
Store: Get-AppxPackage *windowsstore* | Remove-AppxPackage
Sports: Get-AppxPackage *bingsports* | Remove-AppxPackage
Voice Recorder: Get-AppxPackage *soundrecorder* | Remove-AppxPackage
Weather: Get-AppxPackage *bingweather* | Remove-AppxPackage
Xbox: Get-AppxPackage *xboxapp* | Remove-AppxPackage

Nicht entfernen kann man „Support Contact“, „Cortana“, „Windows Feedback“ und den „Edge“ Browser.

Mit folgendem Befehl kann man sich wieder alle Apps automatisch installieren:

Get-AppxPackage -AllUsers| Foreach {Add-AppxPackage -DisableDevelopmentMode -Register “$($_.InstallLocation)\AppXManifest.xml”}
November 10

Windows 2012 R2 Daten Deduplizierung

Mit dem Windows Server 2012 (R2) hat ein neues Feature einzug gehalten, die Data Deduplication. Diese habe ich nun mal getestet und möchte hier ein paar Kleinigkeiten dazu schreiben.

Allgemeines:

  • Data Deduplication ist Clusterfähig (jedoch keine Cluster Shared Volumes)
  • Komprimierte und/oder verschlüsselte Daten können nicht dedupliziert werden
  • Weder das System noch das Boot Volume können dedupliziert werden
  • Das Dateisystem muss NTFS sein
  • Dateien kleiner als 32KB werden nicht deduliziert

Funktionsweise:

Alle Datein werden in kleine Segmente variabler Größe (32 bis 128 kB) zerlegt und im Chunk Store abgelegt. Doppelte Segmente werden verworfen, stattdessen wird an dieser Stelle ein Reparse Point auf dem Dateisystem angelegt welcher auf das entsprechende Segment im Chunk store referenziert. Die Deduplizierung läuft als Hintergrundprozess und evalziert die Daten alle 60 Minuten im Standard.

Vorabtest:

Nach der Server Feature Installation steht einem das Tool „ddpeval.exe“ zur Verfügung mit welchem man (auch auf einem 2008 Server) vorab prüfen kann, ob sich die Deduplizierung lohnen wird. Das Tool zieht ca. 30% CPU und 250 MB Hauptspeicher, bei großen Datenmengen sollte man das ggf. über Nacht laufen lassen. Siehe Technet.

Installation:

Das Dedup Feature kann über den Server Manager oder über die PowerShell nachinstalliert werden:

import-module ServerManager
add-windowsfeature fs-data-deduplication

Im Anschluss muss die Deduplizierung pro Volume eingestellt werden, das geht bequem über die GUI oder PowerShell:

dedup1dedup2

An dieser Stelle kann man gleich eine Throughput Optimization mit einplanen, diese lasse ich 1x pro Woche für maximal 12 Stunden laufen.

Im Anschluss kann man die Deplizierung via PowerShell anstarten:

Start-DedupJob D: -Type optimization -Wait

Das dies etwas dauern und Resourcen verschlingen wird sollte klar sein… ;-)

 

PowerShell:

Es gibt folgende CMDlets:

dedup4

 

Wartung:

Die geplanten Wartungsaufgaben befinden sich in der Task Scheduler Library unter \Microsoft\Deduplication.

Neben dem manuell hinzugefügten ThroghputOptimization Job gibt es noch eine BackgroundOptimization sowie WeeklyGarbageCollection und WeeklyScrubbing.