A- A A+

Task Scheduler en Powershell

Binnen mijn AD domein heb ik een FTP server ingericht met IIS van server 2012. Hierbij is het mogelijk om vanaf een willekeurige locatie doormiddel van FTP in te loggen en toegang te verkrijgen tot resources.

De resources voor de FTP server staan op een fileserver en zijn onder andere de home-folder en wat generieke data. Om dit aan de praat te krijgen via “isolation” binnen IIS dient iedere gebruiker een “home” folder te krijgen op de IIS server. Dit kan gedaan worden door een folder aan te maken of doormiddel van een Virtual Directory. Nu heb ik mijn home-folders op een speciale wijze ingericht onder een users-share welke er als volgt uit ziet:

\\<FILESERVER>\Users$\<username>\Home

Waarbij de mapping in het domein plaats vindt naar Home en niet naar <Username>". Onder de "Home" folder bevinden zich de folders Documents, Pictures, Videos, Etcetera.... Het voordeel van deze methode is dat bij openen van de Users$-share niet iedere folder weergegeven wordt als Mijn Documenten en naast Home ook andere data geplaatst kan worden, zoals bijvoorbeeld speciale folders voor RES Powerfuse/Workspace Manager, Roaming Profiles of wat dan ook. In mijn thuis lab ziet de folder er als volgt uit:

\\<FILESERVER>\Users$\<Username>
\\<FILESERVER>\Users$\<Username>\Home
\\<FILESERVER>\Users$\<Username>\Profile.V2
\\<FILESERVER>\Users$\<Username>\Profile-Ctx.V2
\\<FILESERVER>\Users$\<Username>\Profile-W8.V2
\\<FILESERVER>\Users$\<Username>\Profile-W81.V2
\\<FILESERVER>\Users$\<Username>\PwrMenu-XA6
\\<FILESERVER>\Users$\<Username>\PwrMenu-XA65

Nu wil ik niet iedere keer wanneer ik een user aan maak (op welke methode dan ook), op de IIS server iets speciaals doen om deze gebruiker FTP toegang te geven. Om dit te bewerkstelligen laat ik om de zoveel tijd een powershell script lopen welke dit voor mij afhandelt......

Het Powershell script (versie 1)

Dit script ziet er als volgt uit (namen zijn fictief):

$webAdminModule = get-module -ListAvailable | ? { $_.Name -eq "webadministration" }
If ($webAdminModule -ne $null) {
  Write-Host -foregroundcolor DarkCyan "Importing IIS7 Module WebAdministration"
  Import-Module WebAdministration
}
$cfgSiteName = "userftp.contoso.com"
$cfgFileServer = "FILESERVER"
$cfgUserShare= "\\" + $cfgFileServer + "\Users"
$cfgNetBiosDomain = "contoso"
get-childitem $cfgUserShare | Where-Object { $_.PSIsContainer } | Foreach-object {
  Write-Host -foregroundcolor DarkGreen 'Processing user: ' $_
  $cfgDocPhysicalFolder = "\\" + $cfgUserShare+ "\" + $_ + "\Home"
  $cfgDocVirtualFolder = "usr\" + $_
  if (-not (Test-Path -path IIS:\Sites\$cfgSiteName\$cfgDocVirtualFolder)) {
    Write-Host -foregroundcolor DarkGreen "Create Virtual Folder: " -NoNewLine;
    Write-Host -foregroundcolor Green $cfgSiteName\$cfgDocVirtualFolder;
    $commitpath = 'IIS:\Sites\' + $cfgSiteName + '\' + $cfgDocVirtualFolder;
    New-Item $commitpath -PhysicalPath $cfgDocPhysicalFolder -Type VirtualDirectory
  }
  $cfgDocVirtualFolder = $cfgNetBiosDomain  + "\" + $_
  if (-not (Test-Path -path IIS:\Sites\$cfgSiteName\$cfgDocVirtualFolder)) {
    Write-Host -foregroundcolor DarkGreen "Create Virtual Folder: " -NoNewLine;
    Write-Host -foregroundcolor Green $cfgSiteName\$cfgDocVirtualFolder;
    $commitpath = 'IIS:\Sites\' + $cfgSiteName + '\' + $cfgDocVirtualFolder;
    New-Item $commitpath -PhysicalPath $cfgDocPhysicalFolder -Type VirtualDirectory
  }
}

Wat doet het script

Het script doet een aantal acties:

  1. Controleer of de module voor IIS is geïmporteerd
  2. Importeert de module WebAdministration wanneer dit nog niet is gedaan
  3. Bladert door de users$-share en filtert op containers (dit zijn de home-folders van de gebruikers)
  4. Daarin wordt voor iedere folder gekeken of er een Virtual folder bestaat met de naam virtual server/usr/<username> en indien deze niet bestaat wordt deze aangemaakt
  5. Dan wordt er voor iedere gebruiker gekeken of de Virtual folder met de naam virtual server/<domeinnaam>/<username> bestaat, en bestaat deze niet wordt deze aangemaakt

De virtual folder <domeinnaam> is een fysieke folder buiten de site-root (virtual) met het attribuut “hidden”.

Het probleem

Wanneer de Task Scheduler gebruikt wordt treden er een aantal problemen op:

  1. Standaard mogen er geen powershell scripts worden uitgevoerd (security)
  2. Het account waaronder de task scheduler wordt opgestart heeft te weinig rechten

Er mogen geen powershell scripts worden uitgevoerd

Om dit op te lossen is er een Group Policy object aangemaakt. Dit object ziet er als volgt uit:

image

Dit zorgt ervoor dat er op servers voldoende rechten is om lokale powershell scripts uit te voeren.

Te weinig rechten

Daarnaast heeft het account waaronder de task wordt uitgevoerd te weinig rechten. Om dit te bewerkstelligen is het volgende nodig:

image

Het Run with highest priveleges zorgt er voor dat het script niet door UAC wordt geblokkeerd. Daarnaast moet powershell met de juiste parameters worden aangeroepen:

image

Het powershell script versie 2

Versie 2 is geboren uit noodzaak, standaard had iedere gebruiker read,write in de root van de FTP site, het nadeel was dat mensen onder /usr en /home zelf folders konden aanmaken. Om dit te voorkomen heb ik de hele FTP site dus op read staan, maar dat zorgt er ook voor dat gebruikers niet meer bij hun folders kunnen komen en er kunnen schrijven.

Zie hier, dus versie 2, deze zet ook de rechten op de virtual folder:

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Web.Administration")
$webAdminModule = get-module -ListAvailable | ? { $_.Name -eq "webadministration" }

If ($webAdminModule -ne $null) {
  Write-Host -foregroundcolor DarkCyan "Importing IIS7 Module WebAdministration"
  Import-Module WebAdministration
}
$cfgSiteName = "ftpserver-virtual-site-name"
get-childitem \\wlsmwfsp001\users$ | Where-Object { $_.PSIsContainer } |
  Foreach-object {
    Write-Host -foregroundcolor DarkGreen 'Processing user: ' $_
    
    $cfgDocVirtualFolder = "usr"
    $cfgDocPhysicalFolder = "\\<FILESERVER>\Users$\" + $_ + "\home"
    Write-Host -foregroundcolor DarkGreen "User Home Folder: " $cfgDocPhysicalFolder

    if (-not (Test-Path -path IIS:\Sites\$cfgSiteName\$cfgDocVirtualFolder\$_)) {
       Write-Host -foregroundcolor DarkGreen "Create Virtual Folder: " -NoNewLine;
       Write-Host -foregroundcolor Green $cfgSiteName\$cfgDocVirtualFolder;
       $commitpath = 'IIS:\Sites\' + $cfgSiteName + '\' + $cfgDocVirtualFolder + '\' + $_;
       New-Item $commitpath -PhysicalPath $cfgDocPhysicalFolder -Type VirtualDirectory;
       
       $iis = new-object Microsoft.Web.Administration.ServerManager;
       $config = $iis.GetApplicationHostConfiguration();

       $userURI = $cfgSiteName + "/" + $cfgDocVirtualFolder + "/" + $_;
       Write-Host -foregroundcolor DarkGreen "Get Security: " -NoNewLine;
       Write-Host -foregroundcolor Green $userURI;
       $authorizationSection = $config.GetSection("system.ftpServer/security/authorization",$userURI);
       $authorizationSection;
       $authorizationCollection = $authorizationSection.GetCollection();
       $element = $authorizationCollection[0];
       $attribute = $element.Attributes["Users"];
       Write-Output "Current: " + $attribute.Value.ToString();

       $element["permissions"]= "Read,Write";
       $iis.CommitChanges();   
    }
    $cfgDocVirtualFolder = "home"
    if (-not (Test-Path -path IIS:\Sites\$cfgSiteName\$cfgDocVirtualFolder\$_)) {
       Write-Host -foregroundcolor DarkGreen "Create Virtual Folder: " -NoNewLine;
       Write-Host -foregroundcolor Green $cfgSiteName\$cfgDocVirtualFolder  + '\' + $_;
       $commitpath = 'IIS:\Sites\' + $cfgSiteName + '\' + $cfgDocVirtualFolder + '\' + $_;
       New-Item $commitpath -PhysicalPath $cfgDocPhysicalFolder -Type VirtualDirectory;

       $iis = new-object Microsoft.Web.Administration.ServerManager;
       $config = $iis.GetApplicationHostConfiguration();
    
       $userURI = $cfgSiteName + "/" + $cfgDocVirtualFolder + "/" + $_;
       Write-Host -foregroundcolor DarkGreen "Get Security: " -NoNewLine;
       Write-Host -foregroundcolor Green $userURI;
       $authorizationSection = $config.GetSection("system.ftpServer/security/authorization",$userURI);
       $authorizationSection;
       $authorizationCollection = $authorizationSection.GetCollection();
       $element = $authorizationCollection[0];
       $attribute = $element.Attributes["Users"];
       Write-Output "Current: " + $attribute.Value.ToString();

       $element["permissions"]= "Read,Write";
       $iis.CommitChanges();
       }
  }