I am hoping for some guidance. I need to analyze multiple shares for folders that have not been modified in 6 months. For each share, I defined specific paths that need to be examined. A csv should be generated for each share. The powershell script works fine for checking a single share but I can't get it work correctly for multiple shares. Here's a sample of the script.
$age = (Get-Date).AddMonths(-6)
# Export path
$outputPath = "D:\Scripting\xPowershell_Results\"
# Export file name
$FilePath1 = "OldMediaPath1.csv"
$FilePath2 = "OldMediaPath2.csv"
# Paths to scan
$CheckPath1 = #(
"\\servername\share1\Projects"
"\\servername\share1\Restored"
)
$CheckPath2 = #(
"\\servername\share2\Graphics"
)
$folders = dir $CheckPath1 | where {$_.PSiscontainer -eq $true} | Where-Object {($_.LastWriteTime -lt $age)}
$results = foreach ($folder in $folders) {
$bytecount = (dir $folder.fullname -recurse | Measure-Object -property length -sum).sum
switch ($bytecount)
{
{$_ -lt 1KB} { $size = "{0:N0} Bytes" -f $_; break }
{$_ -lt 1MB} { $size = "{0:N2} KB" -f ($_ / 1KB); break }
{$_ -lt 1GB} { $size = "{0:N2} MB" -f ($_ / 1MB); break }
{$_ -lt 1TB} { $size = "{0:N2} GB" -f ($_ / 1GB); break }
{$_ -lt 1PB} { $size = "{0:N2} TB" -f ($_ / 1TB); break }
default { $size = "{0:N2} PB" -f ($_ / 1PB) }
}
[PSCustomObject]#{
Name = $folder.fullname
Size = $size
LastWriteTime = $folder.LastWriteTime
}
}
$results | Export-Csv $outputPath$FilePath1 -NoTypeInformation
Related
I need help optimizing my PowerShell script.
$sorted = #()
$firsttime = 0
$j = 0
$zaehler = $results.Count-1
for ($i=0; $i -le $results.Count-1; $i++) {
$j = $i+1
while ($results.GUID[$i] -eq $results.GUID[$j]) {
$klassen = ""
$rec = $results | where {$_.GUID -eq $results.GUID[$i]}
if ($firsttime -eq 0 -or !$sorted.GUID.contains($rec[0].GUID)) {
$firsttime = 1
foreach ($item in $rec.Klasse) {
if ($klassen -eq "") {
$klassen += $item
} else {
if (!$klassen.Contains($item)) {
$klassen += "," + $item
}
}
}
$rec[0].Klasse = $klassen
$sorted += $rec[0]
}
$j = $j+1
}
Write-Host ($i/$zaehler).ToString("P") "von Schule" $schule
}
if (!$sorted) {
$results
} else {
$sorted
}
Basically in my resultset ($results) I got duplicate lines of teachers and the only difference is the class ("Klasse/Klassen") they are teaching at.
To minimize the output I am checking if the first GUID is the same as the second and then the script appends the second class to the first one. So the $sorted array has just one line per teacher with a comma-seperated string which shows all classes.
Sample line of $results:
#{
GUID={1234567-1234-1234-1234-1234567};
userrole=teacher;
Vorname=Max;
Nachname=Mustermann;
Geburtstag=01.01.2000;
Klasse=9A;
Schule=123456
}
#{
GUID={1234567-1234-1234-1234-1234567};
userrole=teacher;
Vorname=Max;
Nachname=Mustermann;
Geburtstag=01.01.2000;
Klasse=9B;
Schule=123456
}
Sample line of $sorted[0]:
#{
GUID={1234567-1234-1234-1234-1234567};
userrole=teacher;
Vorname=Max;
Nachname=Mustermann;
Geburtstag=01.01.2000;
Klasse=9A,9B,9C,5A;
Schule=123456
}
The sorting process (check if contains, foreach $item, add to $klassen) is pretty slow.
I would be very grateful for any kind of ideas how to optimize the script.
Maybe something like this would work:
$results | ForEach-Object {
New-Object -Type PSObject -Property $_
} | Group-Object GUID | ForEach-Object {
$teacher = $_.Group
$teacher | Select-Object -First 1 -Exclude Klasse -Property *, #{n='Klasse';e={
$teacher | Select-Object -Expand Klasse
}}
}
Convert your hashtables into custom objects, group them by GUID, then replace the original "Klasse" property with a new one containing an array of the values from all objects in that group, and select the first result.
Should $results already be a list of objects you can skip the first ForEach-Object:
$results | Group-Object GUID | ForEach-Object {
$teacher = $_.Group
$teacher | Select-Object -First 1 -Exclude Klasse -Property *, #{n='Klasse';e={
$teacher | Select-Object -Expand Klasse
}}
}
I am trying to do a nested loop in PowerShell. I am renaming images in a several sub directories but i need the loop to reset based on it finding a new directory.
Here is the code I wrote but I can't get it to work as it gives me an error saying the file doesn't exist.
function rename-cruise {
Param([string]$parkname, [string]$extension=".jpg")
if(!$parkname){
$park = $args[0];
} else {
$park = $parkname;
}
$dirs = Get-ChildItem -Recurse | ?{ $_.PSIsContainer };
foreach($dir in $dirs){
if($dir -cnotlike "177"){
$i = 0;
$currentDir = get-location;
$location = "$currentDir\$dir";
write-host $currentDir
write-host $location
Get-ChildItem -Path $location -Filter "*$extension" |
ForEach-Object {
if($i -lt 10){
$newName = "$park-0$i$extension";
Rename-Item $_.Name -NewName $newName;
} else {
$newName = "$park-$i$extension";
Rename-Item $_.Name -NewName $newName;
}
$i++;
}
}
}
}
I have an *.ics file and want to import it to my calendar on outlook.com. How can I do this with a powershell script?
I need to either delete and recreate the calendar I import to, or clear the calendar before import.
Thanks in advance.
Try
Step 1: Read the contents of the ics file
Step 2: Parse it
Step 3: Use Outlook Application Object in Powershell
Step 4: Get the Calendar folder
Step 5: use the properties of the calendar folder to add the parsed content in step 2
#Folder containing ICS files
$ICSpath="C:\Users\test\testasdasd"
$ICSlist = get-childitem $ICSPath
Foreach ($i in $ICSlist )
{
$file= $i. fullname
$data = #{}
$content = Get-Content $file -Encoding UTF8
$content |
foreach-Object {
if($_.Contains(':')){
$z=#{ $_.split( ':')[0] =( $_.split( ':')[1]).Trim()}
$data. Add( $z. Keys, $z. Values)
}
}
$outlook = new-object -com Outlook.Application
$calendar = $outlook.Session.GetDefaultFolder(9)
$appt = $calendar.Items.Add(1)
$Body=[regex]::match($content,'(?<=\DESCRIPTION:).+(?=\DTEND:)', "singleline").value .trim ()
$Body= $Body -replace "\r\n\s"
$Body = $Body.replace("\,",",").replace("\n"," ")
$Body= $Body -replace "\s\s"
$Start = ($data.getEnumerator() | ?{ $_.Name -eq "DTSTART"}).Value -replace "T"
$Start = [datetime]::ParseExact ($Start ,"yyyyMMddHHmmss" ,$null )
$End = ($data.getEnumerator() | ?{ $_.Name -eq "DTEND"}).Value -replace "T"
$End = [datetime]::ParseExact ($End ,"yyyyMMddHHmmss" ,$null )
$Subject = ($data.getEnumerator() | ?{ $_.Name -eq "SUMMARY"}).Value
$Location = ($data.getEnumerator() | ?{ $_.Name -eq "LOCATION"}).Value
$appt.Start = $Start
$appt.End = $End
$appt.Subject = $Subject
$appt.Categories = "Presentations" #Pick your own category!
$appt.BusyStatus = 0 # 0=Free
$appt.Location = $Location
$appt.Body = $Body
$appt.ReminderMinutesBeforeStart = 15 #Customize if you want
$appt.Save()
if ($appt.Saved)
{ write-host "Appointment saved."}
Else {write-host "Appointment NOT saved."}
}
Acknowledging "thescriptkeeper.wordpress.com" for the script
I need to generate usernames that start with a letter of the alphabet, followed by the date and that ends with numbers from 1 to 20. For a total of 520 names.
Here's the variables I came up with:
$letter = 97..122 | foreach {[char]$_}
$date = get-date -UFormat %a%y%d
$name = $letter | ForEach-Object { $_ + $date }
So I managed to put my letters and my dates together, to form names like aWed1513, which is exactly what I need, but when it comes to make each to end with numbers, I'm stuck. Tried with a For loop by adding incrementing $i to $name, but doesn't work..
It seems like you're just about there. Your for loop should look like this:
$names = #()
$letter = 97..122 | foreach {[char]$_}
$date = get-date -UFormat %a%y%d
for($i = 1; $i -le 20; $i++) {
$names += $letter | ForEach-Object { '{0}{1}{2}' -f $_, $date, $i }
}
$names
An alternate approach to the answer given that just adds another ForEach-Object to the OP's original code:
$letter = 97..122 | foreach {[char]$_}
$date = get-date -UFormat %a%y%d
$names = $letter | ForEach-Object { $_ + $date } | ForEach-Object { for($i=1;$i -le 20;$i++) { $_ + $i } }
And to shorten to get same result:
$letter = 97..122 | foreach {[char]$_}
$date = get-date -UFormat %a%y%d
$names = $letter | ForEach-Object { for($i=1;$i -le 20;$i++) { $_ + $date + $i } }
I am trying to find all file extension in a folder and subfolders and generate a list. I found a oneliner but it do not generate the list as i want. i got mutiple of paths so i do this.
$date = get-date -Format d
$File = "C:\NoBackup\FolderPaths.txt"
foreach ($Folder in (Get-Content $File)) {
Get-ChildItem $Share -Recurse -ErrorAction SilentlyContinue | Group-Object extension | Select-Object #{Name="Folder";Expression={$Folder}}, name, #{n='TotalSize';e={$_.group | ForEach-Object -Begin {$size=0} -Process {$size += ([decimal]::round($_.Length / 1MB))} -End {"$size MB"}}} | Sort-Object -Property 'TotalSize' -Descending | Format-Table -AutoSize
}
This will give a new header foreach folder in folderpaths, and i need the result be like this
.ext1 .ext2 .ext3 .ext4
D:\Folder1 5MB 12MB 20MB 8MB
D:\Folder2 10MB 54MB 12MB 3MB
D:\Folder3 2MB 12MB 20MB 100MB
I cant find out to rewrite the code to get what i need. Hope you can help me out with this.
The script works now. I needed to change
foreach($folder in $folders)
To
foreach($folder in (Get-Content $file))
It is not short or sweet, but try this:
function ConvertTo-Units($decimal)
{
$value = [decimal]::Round($decimal/1mb,2)
$units = "MB"
if($value -eq 0)
{
$value = [decimal]::Round($decimal/1kb,2)
$units = "KB"
}
return "{0} {1}" -f $value,$units
}
$File = "C:\NoBackup\FolderPaths.txt"
$fileData = #{}
foreach ($folder in (Get-Content $file))
{
$files = Get-ChildItem $folder -Recurse -ErrorAction SilentlyContinue -File
$fileData[$folder] = $files | Select-Object extension,length | %{$h = #{}} { $h[$_.extension] += $_.length } { $h}
}
$extensions = $fileData.Keys | % { $fileData[$_].Keys } | % tolower | Select-Object -Unique | ? { $_ }
$properties = #(
#{Name="Folder";Expression={$_}}
)
$extensions | % {$properties += #{Name="$_";Expression=[scriptblock]::Create("ConvertTo-Units `$fileData[`$folder][""$_""]")}}
$result = #()
foreach($folder in $folders)
{
$result += $folder | Select-Object $properties
}
$result | ft * -AutoSize -force