Komplett säkerställning av identitet mot navet med Powershell

This post is going to be in Swedish since it’s an custom-made integration against Swedish tax authority.

För tillfället pågår ett projekt hos oss där man har behov av att styrka identitet mot skatteverkets e-tjänst “Navet”. Projektet hade förhoppningar på att leverantörer av personalsystem eller motsvarande skulle kunna ta ansvar för konvertering och transport av data mot navet, men det var tydligen inget de kunde göra. Tieto hade flaggat för att de skulle kunna göra jobbet mot en säck pengar, dock ville man under testfasen komma igång så snabbt som möjligt och frågade mig och en kollega om vi skulle kunna vara hjälpliga och kanske ratta det manuellt under testet för att få momentum i projektet. Manuellt arbete är trist så jag satte upp allt med hjälp av 4 stycken powershell-script som vi framtiden kommer kunna återanvända i produktion. Svårigheterna i utvecklingen låg i bland annat att skatteverket rekommenderar ett freewareprogram som heter curl för att hämta och lämna filer och här ville jag göra allt med ren powershell, samt att skatteverket inte använder xml eller csv utan istället vad jag tror är någon hemmasnickrat stordatorformat(Och ja det kanske är ISO-standard sen 1967? men det är inte lättjobbat för det). Flödesschema för lösningen:

Slagning Navet flöde

Först exporteras en lista med en kolumn med personnummer från Heroma. Vi tar den listan och konverterar till  Navetkompatibelt format genom att köra det första skriptet av fyra. Navetfilen ska se ut på följande sätt:

#INFO_START
#FILTYP INDATAFIL
#BESTÄLLNINGSID XXXXXXXXX-XXXX-XXXXX
#BESTÄLLNINGSTYP URVAL
#NAMN_INFIL datafil.txt
#GILTIG_TOM XXXXXX
#INFO_SLUT
#DATA_START
#PNR 1927XXXXXXXX
#PNR 1928XXXXXXXX
#PNR 1939XXXXXXXX
#DATA_SLUT
#AVST_START
#ANTAL_POSTER 00000003
#AVST_SLUT
#FIL_SLUT

Jag löste konverteringen genom att skapa skapa 3 stycken textfiler med data som är statisk, sen skapa 2 st filer varje körning med datat som är dynamisk, dvs personnummer och antal poster. skriptet blev så här och gjorde jobbet:

##################################################
#Name: Convert_infile.ps1
#Aurthor: Viktor Lindström 
#
#Comments: Converts Heromfile with personal identity number to Navet compatible Infil file.
##################################################


#Variables
$personer = Get-Content "C:\PKI\personnummer.txt" | Sort-Object
$file2sökväg = "C:\pki\file2.txt"
$file4sökväg = "C:\pki\file4.txt"
$alldatafile = "C:\pki\datafil.txt"
#Count persons and add up with zeros
$antal_personer = "{0:D8}" -f $personer.Count


#Delete file2.txt if it exists.
if (test-path $file2sökväg)
{Remove-Item -Path $file2sökväg
    
}

#Delete file4.txt if it exists.
if (test-path $file4sökväg)
{Remove-Item -Path $file4sökväg
    
}

#Delete alldata.txt if it exists.
if (test-path $alldatafile)
{Remove-Item -Path $alldatafile
    
}

#Create Navet-compatible personal number 
foreach ($person in $personer)
{$person.Replace($person, "#PNR $person") | add-Content $file2sökväg 
    }


#Create Navet-compatible ANTAL_POSTER
Add-Content -Path $file4sökväg -Value "#ANTAL_POSTER $antal_personer"

#Import textfiles.
$file1 = Get-Content C:\PKI\file1.txt
$file2 = Get-Content C:\PKI\file2.txt
$file3 = Get-Content C:\PKI\file3.txt
$file4 = Get-Content C:\PKI\file4.txt
$file5 = Get-Content C:\PKI\file5.txt

#Add all data in one variable
$alldata = $file1+$file2+$file3+$file4+$file5

#Create NAvet infile
Add-Content -Path $alldatafile -Value $alldata

Steg två var att lämna filen med hjälp av powershell istället för rekommenderade curl. Det här var enklare än jag trodde först en enkel import av ett certfikat och sen invoke-webrequest med method post och peka ut filen:

 

##################################################
#Name: Push_infil.ps1
#Aurthor: Viktor Lindström 
#
#Comments: Uploads Navet Infil file to skatteverket navet e-transport.
##################################################

#Variabels
$produktidentitet = "xxxxxxxxx-xxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxxx-xxxxxxxx"
$infil = "C:\pki\datafil.txt"

#get certificate
$certificate = Get-ChildItem -Path cert:\CurrentUser\My | where dnsnamelist -Like "*skatte*"

#Upload to Skatteverket
Invoke-WebRequest -Uri "https://shs.skatteverket.se/et/et_web/auto/$produktidentitet" -CertificateThumbprint $certificate.Thumbprint -Method Post -InFile $infil 

Efter att skatteverket fått våran fil så säkerhetsställer de identiteten mot sin databas och fyller på med för, efterenamn, etc etc… och skapar en fil som vi får hämta på ungefär samma sätt som vi lämnade men med skillnaden att vi gör en fråga mot en URL och i content:en så svarar skatteverket med slutet på URL där vi kan hämta filen:

 

##################################################
#Name: get-utfil.ps1
#Aurthor: Viktor Lindström 
#
#
#
#Comments: Downloads Navet Utfil file from skatteverket navet e-transport.
##################################################


#Variabels
$produktidentitet = 'xxxxxxxxx-xxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxxx-xxxxxxxx'

#URL to check filename
$checkpatpath = "https://shs.skatteverket.se/et/et_web/auto/" + $produktidentitet + "?getfilenames=true"

#get certificate
$certificate = Get-ChildItem -Path cert:\CurrentUser\My | where dnsnamelist -Like "*skatte*"

#Upload to Skatteverket
$Filecheck = Invoke-WebRequest -Uri "$fullpath"  -CertificateThumbprint $certificate.Thumbprint  

#
$getpath = "https://shs.skatteverket.se/et/et_web/auto/" + $produktidentitet + "/" + $Filecheck.Content

$date = get-date -Format d

Invoke-WebRequest -Uri $getpath -CertificateThumbprint $certificate.Thumbprint -OutFile c:\pki\$date.txt

Det sista och för mig svåraste steget var sen att konvertera Navets fil till en Heromakompatibel csv-fil. Navets fil såg ut på följande sätt där varje kod motsvarar tex förnamn efternam etc etc…:

#INFO_START
#FILTYP UTDATAFIL
#BESTÄLLNINGSID XXXXXXXX-XXXXX-XXX
#BESTÄLLNINGSTYP URVAL
#EFFEKTUERAD 20150110
#INFIL_TILL_GRUND datafil.txt
#INFO_SLUT
#DATA_START
#POST_START
#UP 01001 1958XXXXXXXX
#UP 01012 Ulf Bengt
#UP 01014 Lundell
#POST_SLUT
#POST_START
#UP 01001 1975XXXXXXXX
#UP 01012 Jul
#UP 01014 Tomten
#POST_SLUT
#POST_START
#UP 01001 1978XXXXXXXX
#UP 01011 20
#UP 01012 Carl Christer
#UP 01014 Lopez
#POST_SLUT
#DATA_SLUT
#AVST_START
#ANTAL_POSTER 00000003
#AVST_SLUT
#FIL_SLUT

Jag hade lite olika idéer för hur jag skulle lösa konverteringen men landade till slut i lösning där jag kör select-string mot alla koder kan tänkas komma  och fyller sen en ny fil med de raderna, här plockar jag också bort citationstecken samt fyller på med kommatecken för att få till en csv där jag även lägger till två headers(code och value), nu har jag en csv med kod och värde. När vi rensat datat på allt ointressant så gäller det att börja sortera in det i en Heromakompatibel csv-fil. Jag börjar med att bygga en tom array variabel med alla headers som heroma vill ha och sedan kör jag en foreach på varje rad ur den tvättade datafilen med en switch där jag fyller på de olika fälten i den tom array:en . När en rad gått klart så kollar den om fälten personnummer förnamn och efternamn är fulla, om de är det så  exporteras array:en till en csv och därefter töms alla noteproperty i array:en. skriptet ser ut så här:

##################################################
#Name: Konvertering utfil.ps1
#Aurthor: Viktor Lindström 
#
#
#
#Comments: Converts Navet Utfil-file to Heroma compatible file
#Rev1.01(2015-01-15 Added Code 01003 because of secrecy
#Rev1.02(2015-01-15 replaced out-file to set-content to have ANSI encodeing. Line 79
##################################################

#File variables
$date = get-date -Format d

$sourcefile = "C:\pki\" + $date + ".txt"
$workfile = "C:\pki\workfile.txt"
$resultfile = "C:\pki\resultat.txt"
$heromafile = "C:\pki\heroma.txt"

#Filter working posts
$content = Get-Content $sourcefile -Encoding UTF7
$content | Select-String "#UP 01001","#UP 01002", "#UP 01012", "#UP 01014", "#UP 01011", "#UP 01013","#UP 01003"  | Set-Content $workfile -Encoding UTF8

#Wash away unwanted data and replace space between code and value with comma.
$content2 = Get-Content $workfile -Encoding UTF8
$content2 | foreach {$_ -replace "#UP 01001 ", "01001,"} | set-content $workfile -Encoding UTF8
$content2 = Get-Content $workfile -Encoding UTF8
$content2 | foreach {$_ -replace "#UP 01014 ", "01014,"} | set-content $workfile -Encoding UTF8
$content2 = Get-Content $workfile -Encoding UTF8
$content2 | foreach {$_ -replace "#UP 01012 ", "01012,"} | set-content $workfile -Encoding UTF8
$content2 = Get-Content $workfile -Encoding UTF8
$content2 | foreach {$_ -replace "#UP 01011 ", "01011,"} | set-content $workfile -Encoding UTF8
$content2 = Get-Content $workfile -Encoding UTF8
$content2 | foreach {$_ -replace "#UP 01013 ", "01013,"} | set-content $workfile -Encoding UTF8
$content2 = Get-Content $workfile -Encoding UTF
$content2 | foreach {$_ -replace "#UP 01003 ", "01003,"} | set-content $workfile -Encoding UTF8
$content2 = Get-Content $workfile -Encoding UTF8
$content2 | foreach {$_ -replace "#UP 01002 ", "01002,"} | set-content $workfile -Encoding UTF8


# Create CSV with headers.
$import = Import-Csv $workfile -Encoding UTF8 -Delimiter "," -Header Code, Value

#
$row = "" | select "Personnummer","Tilltalsnamnsmarkering", "Förnamn", "Mellannamn", "Efternamn","Fullständigt namn","C/O adress","Utdelningsadress 1","Utdelningsadress 2","Postnummer","Postort","Anonym"

#Delete resultfile if it exists.
if (test-path $resultfile)
{Remove-Item -Path $resultfile
    
}

foreach ($item in $import)
  { switch ($item.Code) {
    "01001" {$row.Personnummer = $item.value}
    "01002" {$row.Personnummer = $item.value}
    "01003" {$row.Anonym = $item.value}
    "01011" {$row.Tilltalsnamnsmarkering = $item.value}
    "01012" {$row.förnamn = $item.value}
    "01013" {$row.Mellannamn = $item.value}
    "01014" {$row.Efternamn = $item.value}tömms alla 

   }
    
                      
        if ($row.Personnummer -ne $null -And $row.Förnamn -ne $null -and $row.Efternamn -ne $null)
                { 
              
                $row | export-csv $resultfile  -Append -NoTypeInformation -Encoding UTF8 -Delimiter ";"
                $row.personnummer = $null
                $row.förnamn = $null
                $row.efternamn = $null
                $row.Tilltalsnamnsmarkering = $null
                $row.Mellannamn = $null
                $row.Anonym = $null
                
                    
                    
                               }

                               }
                               

#Remove qotations marks and delete headlines and convert to ANSI
                               Get-content $resultfile | % {$_ -replace '"', ""} | select -Skip 1| set-content $heromafile

Vid testkörning mot Navet så fungerade alla skript som de skulle och vi slapp skriva tusentals rader för hand. Om den här lösningen landar i produktion i en system center orchestrator eller som schemalagda skript eller om man väljer att köpa konvertering och transport återstår att se, dock kan man få till en fullständig säkerhetställning av identitet mot Navet genom att endast använda sig av Powershell.

How to upload files to Skatteverkets navet e-transport with powershell

skatteverketWhen you want to collateral an identity against the Swedish tax agency Skatteverkets service Navet one part of the process is to upload a bulk file to their service “E-transport”. In Skatteverkets technical documentation they recommend freeware program curl in windows environments, but they refer to the developer for support. The upload can easily be done with powershell and invoke-webrequest.

#Variabels
$produktidentitet = "xxxxxxxxxx-xxxxx-xxxx-xxxx-xxxxxxxxxxxxx"
$infil = "C:\temp\datafil.txt"

#get certificate
$certificate = Get-ChildItem -Path cert:\CurrentUser\My | where dnsnamelist -Like "*skatte*"

#Upload to Skatteverket
Invoke-WebRequest -Uri "https://shs.skatteverket.se/et/et_web/auto/$produktidentitet" -CertificateThumbprint $certificate.Thumbprint -Method Post -InFile $infil

 

Bulk modify AD users from CSV

The last post showed how to create AD users from CSV, here is how to bulk modify attributes from CSV

#Modify AD user from CSV file, in this case i Change the extensionAttribute1 and extensionAtribute2
#anvandare,test,Url
#viklin,test1,https://www.contoso.com
#tonrim,test2,https://www.contoso.com
#steloz,test3,https://www.contoso.com
$Import=Import-Csv C:\temp\csv.txt
    foreach($user1 in $Import)
        {
    set-aduser $user1.anvandare -Replace @{extensionAttribute1=$user1.test; extensionAttribute2=$user1.Url} 
    }

Bulk create AD users from CSV

In a Facebook group a user asked for a script to create users from CSV, it is very easy:

# $sourceuser store the the user you whant to create users from in an variable
# $import imports CSV in an variable with the users the scv looks like this:
# 
# logon,FirsName,LastName,DisplayName
# klitom,Tommy,Stenstrom,Stenstrom Tommy
# klidoo,Sonny,Ramos,Ramos Sonny
# klikri,Conny,Edwards,Edwards Conny
#
# $ou specifies wich OU you whant to put the users in. 
$sourceuser = get-aduser klidan
$import = import-csv C:\temp\användare.txt
$ou = "OU=Admin,OU=Data,DC=adm,DC=contoso,DC=se"
foreach ($användare in $import)
{

New-ADUser -SamAccountName $användare.logon -UserPrincipalName $användare.logon -Name $användare.DisplayName -GivenName $användare.FirstName -Surname $användare.LastName -DisplayName $användare.DisplayName  -Instance $sourceuser -Enabled $true -path $ou -AccountPassword (Read-Host -AsSecureString "AccountPassword") -ChangePasswordAtLogon $true }

Count users from AD groups

countThis week I got involved in a project regarding licensing on our remote desktop servers. In phase one I had to do a current situation analysis on how many users that can access our different servers. Since we have 5 different departments the project manager also wanted to have information of how many users the different departments had on each server and a separate excel document for each department with all their users listed. The project manager also hinted that in phase 2 after we made actions and before each license audit we might have to create new reports. Since I am lazy and don´t like to manually create reports I made a function in Powershell  where anyone with the active directory-module can create reports.

function get-UsersFromGroup 
{
param
([parameter(mandatory)]
[ValidateSet("srv-rcard01","srv-rds02","srv-procapts01")]
[string] $server)

# Variables for date and exportfile-summary
$date = get-date -Format d
$outfile = "C:\temp\Sammanfattning $server $date.txt"
$tempdir = "C:\temp"

# Get users from AD group depending on server.
switch ($server) {
srv-rcard01 {$users = Get-ADGroupMember r-card_srv-rco01}
srv-rds02 {$users = Get-ADGroupMember "BG Fjärrskrivbord" }
#Since 2 groups with some users in both broups I do a sort-object and unique
srv-procapts01 {$group1 = Get-ADGroupMember Procapita-Funktion-Remoteapp
$group2 = Get-ADGroupMember Procapita-Aldreoms-Remoteapp
$userspro = $group1 + $group2 
$users = $userspro | Sort-Object | Get-Unique}
}

#Get users from group
#$users = Get-ADGroupMember "$group"
$users2 = $users | Get-ADUser -properties * -ErrorAction SilentlyContinue

#build empty arrays
$KSF = @()
$SAF = @()
$BUF = @()
$KUF = @()
$MSB = @()
$Övriga = @()

#Sort by apartment.
foreach ($user in $users2)
{if($user.DistinguishedName -like "*OU=KSF*")
{$KSF +=$user}
 elseif ($user.DistinguishedName -like "*OU=SAF*")
{$SAF +=$user}
 elseif
($user.DistinguishedName -like "*OU=BUF*")
{$BUF +=$user}
 elseif
($user.DistinguishedName -like "*OU=KUF*")
{$KUF +=$user}
 elseif
($user.DistinguishedName -like "*OU=MSB*")
{$MSB +=$user}
else
{$Övriga +=$user}
}

# Write result.
Write-host Sammanlagt är det $users2.count användare
write-host KSF har $ksf.count användare
write-host SAF har $saf.count användare
write-host BUF har $Buf.count användare
write-host KUF har $kuf.count användare
write-host MSB har $msb.count användare
write-host Övriga användare är $övriga.count stycken

#Delete summary-file if it exists.
if (test-path $outfile)
{Remove-Item -Path $outfile
    
}

#Check if dircetory c:\temp exist and if not create it.
if ( -Not (Test-Path $tempdir))
 { New-Item -Path $tempdir -ItemType Directory
 }

# Output count-result to file.
Write-Output "Sammanlagt är det $($users2.count) användare" | Out-File $outfile -Append
Write-Output "KSF har $($ksf.count) användare" | Out-File $outfile -Append
Write-Output "SAF har $($saf.count) användare" | Out-File $outfile -Append
Write-Output "BUF har $($Buf.count) användare" | Out-File $outfile -Append
Write-Output "KUF har $($kuf.count) användare" | Out-File $outfile -Append
Write-Output "MSB har $($msb.count) användare" | Out-File $outfile -Append
Write-Output "Övriga användare är $($övriga.count) stycken" | Out-File $outfile -Append



#Export to CSV to c:\temp\
Write-Host Exporterar alla användare till CSV som läggs i c:\temp\[förvaltning.csv]
$msb | select SamAccountName, GivenName, SurNAme, Description | Export-Csv c:\temp\msb-$server.csv -NoTypeInformation -Encoding UTF8 -Delimiter ";"
$ksf | select SamAccountName, GivenName, SurNAme, Description | Export-Csv c:\temp\ksf-$server.csv -NoTypeInformation -Encoding UTF8 -Delimiter ";"
$buf | select SamAccountName, GivenName, SurNAme, Description | Export-Csv c:\temp\buf-$server.csv -NoTypeInformation -Encoding UTF8 -Delimiter ";"
$kuf | select SamAccountName, GivenName, SurNAme, Description | Export-Csv c:\temp\kuf-$server.csv -NoTypeInformation -Encoding UTF8 -Delimiter ";"
$saf | select SamAccountName, GivenName, SurNAme, Description | Export-Csv c:\temp\saf-$server.csv -NoTypeInformation -Encoding UTF8 -Delimiter ";"
$Övriga | select SamAccountName, GivenName, SurNAme, Description | Export-Csv c:\temp\övriga-$server.csv -NoTypeInformation -Encoding UTF8 -Delimiter ";"

#Capture if there is a group in the result.
foreach ($grupp in $users)
{
if ($grupp.objectclass -like "group") {Write-Host det finns en grupp som heter $grupp.name -BackgroundColor Red }
    }
}

Compare printers on printer servers

Right now I´m working on removing two old printer servers that should have been powered of a couple of years ago. Unfortunately we still have some GPOs mapping the printers to some users with VB scripts. Therefore I need to find out if we have printers on the old servers that haven’t been migrated to the new servers, to accomplish that I collected all printers from the old and new printer servers in different variables and then used compare-object on the printers portname. On the new printer servers we have chosen to place all Toshiba-printers on one server and all Oki and HP on another one, therefore I could easily separate Toshiba printers from the others with an if else  statement filtering on the driver name. The result is a list of all printers that don’t exist on the new servers displaying which printer server the printer exist on and which printer server it needs to be installed on:

“The printer PRN0422 exists on srv-print04 and needs to be installed on srv-print08”

Now the printer/GPO-guy can install the printers on the correct servers and replace the Vb scripts with preferences mapping the same printers but on the new servers.

 

#Get all printers
$srvprint04 = Get-printer -ComputerName srv-print04
$srvprint05 = Get-Printer -ComputerName srv-print05
$srvprint07 = Get-Printer -ComputerName srv-print07
$srvprint08 = Get-Printer -ComputerName srv-print08

#Collect old and new printers in diffrent variables
$printers1 = $srvprint04 + $srvprint05
$printers2 = $srvprint07 + $srvprint08

#Compare if printers exists on new server
$allold= Compare-Object -ReferenceObject $printers2.portname -DifferenceObject $printers1.portname -IncludeEqual | where sideindicator -EQ "=>"

#Display which old server the printer is installed on and which new server it needs to be installed on.
foreach ($printer in $printers1)
{ if ($allold.inputobject -contains $printer.portname   )
  {if ($printer.drivername -like "*tosh*")
    {Write-Host The printer $printer.PortName exists on $printer.ComputerName and needs to be installed on srv-print07
      }
      else
      {Write-Host The printer $printer.PortName exists on $printer.ComputerName and needs to be installed on srv-print08}
  
    }
    

Delete expired accounts in Active Directory

delete

 

In an facebook user group another user asked how to use powershell to delete expired user accounts. He wanted to use excel to store expiration date and username etc etc. Since AD have accountexpirationdate property built in, it is better to use the AD as content database instead of excel. I answers with this simple script and since the reply got the thumbs up i think it solved his problem.

$days_date = Get-Date
$users = get-aduser -Filter 'AccountExpirationDate -LT $days_date'

foreach ($usr in $users)
{Remove-ADUser $usr
}

This is just a simple core to remove users, you could expand the script to for example use a quarantine lets say you want to use a quarantine for 60 days, I would create a quarantine OU and instead of deleting users that has expired “today” i would move them to that OU. After that you could create a new  get-date string but with the add_days method you could remove 60 days so you only remove user accounts older then 60 days:

$date = (get-date).AddDays(-60)

You could also build a log. To do that you could begin with an empty hash table in front of the foreach-loop and then use the name property from the $usr and $get-date do get the date when it was removed, after that you have to use the GetEnumerator method when you export to CSV, it could look something like this:

$date = get-date
$log = @{}
foreach ($usr in $users)
{ 
 $log.Add($usr.name,$date)
    }
$log.GetEnumerator() | select name, value | export-csv -NoTypeInformation C:\test\log.csv

Difference when working with properties in an array in old and new powershell.

Me and an college is currently working on moving the data from an old file server to a new file server with a brand new directory structure. After the files have been migrated we have to move the ACLs on the folders on level two, we where planing on doing this with a powershell script that looked something like this:

$import = Import-Csv C:\test\acl.csv 
 foreach ($row in $import)
{
 Get-acl $row.source | set-acl $row.target  
 }

By using a “.” after the variable to pin-point which property to use. Since the old server is Windows 2008 r2 and uses powershell 2 using the dot to point out proeperties ain`t supported.
I then tried to throw in some variables in the foreach loop with select-item to get the data I needed, unlucky for me this didn´t work either. It looked like this:

$import = Import-Csv C:\test\acl.csv 
  foreach ($row in $import)
{ $source = $row | select source
  $target = $row | select target  

   Get-acl $source | set-acl $target  
 }

The problem here is that “$variable | select property” is an PSCustomObject and get-acl and set-acl wants a string-object. If you pipe the variable to get-member($variable | select property | get-member) you will find out what type you have, in this example it looked like this “TypeName: System.Management.Automation.PSCustomObject”. To get a string you need to use -ExpandProperty with select-item, after doing this the script will work on both old(powershell 2.0) and newer versions and will look like this:

$import = Import-Csv C:\test\acl.csv 
  foreach ($row in $import)
{$source = $row | select -ExpandProperty source
 $target = $row | select -ExpandProperty target 
 
Get-acl -Path $source | set-acl -Path $target  
   }

Function to schedule restart

restartThis monday I had to schedule a restart on a fileserver that weren`t in a cluster, therefore it had to be restarted in the middle of the night. I always have a little trouble when I schedule restarts and have to use google to get it right with the program/script and add argument lines. I decided to create a function where I can specify date and time to schedule the restart. I also put in some other functions as regular expression that checks that date and time is in correct format, deletion of old task with same name, confirmation if you want to create the job and some pop-ups.

#-------------------------------------------------------------
#NAME: schedule_restart.ps1
#AUTHOR: Viktor Lindström
#
#COMMENTS: funtion to schedule restart on local computer.
#-------------------------------------------------------------

function Set-restartcomputer 
{
<#
 
.SYNOPSIS
This function schedules a restart on the local computer
 
.DESCRIPTION
Parameters date and time are mandatory and have to be writen in following formats time = 00(hr):00(mnt):00(sec) and date 0000(year)-00(month)-00(day)
 
.EXAMPLE
set-restartcomputer -time 16:00:00 -date 2014-09-23
This example creates a scheduled task that restarts the local computer at 16:00:00 the 23 september 2014
 
.NOTES

 
.LINK
 
http://powehell.nu
 
#>

param(
[parameter(mandatory)]
[Validatepattern("^(\d{2}):(\d{2}):(\d{2}$)")]
[string]$time,
[parameter(mandatory)]
[Validatepattern("^(\d{4})-(\d{2})-(\d{2}$)")]
[string]$date
)
$datetime = ($date -as [datetime]).date -replace "00:00:00", $time
$taskname = "RestartComputer"

$job = Get-ScheduledJob -name $taskname -ErrorAction SilentlyContinue

if ($job)
{Unregister-ScheduledJob -name $taskname -ErrorAction SilentlyContinue
    
}


$options = New-ScheduledJobOption -RunElevated -StartIfOnBattery
$trigger = New-JobTrigger -Once -At $datetime

$question = ""
while ($question -notmatch "[y|n]"){
    $question = Read-Host "Do you what to schedule a restart of computer at $datetime ? (y/n)"
    }

    if ($question -eq "y"){
    Register-ScheduledJob -name $taskname -ScriptBlock { Restart-Computer -Force } -Trigger $trigger -ScheduledJobOption $options
    $popup = New-Object -ComObject Wscript.Shell
    $popup.Popup("Operation Completed, a restart on computer has been scheduled to $datetime",0,"Done",0x1)
    }
    
else {$wshell = New-Object -ComObject Wscript.Shell
$wshell.Popup("Run function again",0,"Done",0x1)
}



}

 

 

 

 

 

 

 

 

 

 

Set folder inheritance

 

folder

In the last blogg I wrote in how to find differens in source and target folder inheritance. Here is a scritpt to enable the inheritance on multiple folders listed in an csv-file. The acl.SetAccessruleProtection line only sets the flag and the you have to commit with set-acl, hopefully this will change in future versions.

Had to use google on this one because the strange way to implement this. http://richardspowershellblog.wordpress.com/2008/02/06/file-system-allow-inheritable-permissions-from-parent-to-propagate/

#----------------
---------------------------------------------
#NAME: Set folder inheritance.ps1
#AUTHOR: Viktor Lindström
#
#COMMENTS: Set inheritance behavior on folders 
#-------------------------------------------------------------
$Import = import-csv "c:\test\folders.csv


foreach ($path in $import)
{
$acl= Get-Acl -Path $path 
$acl.AreAccessRulesProtected
$isProtected = $false
$preserveInheritance = $true
$acl.SetAccessRuleProtection($isProtected, $preserveInheritance)
Set-Acl -Path $path -AclObject $acl 
}