I am pretty new in PowerShell scripting so if what I am asking is not possible by all means tell me that.
I would like to create a PowerShell script that would accept the send-to command.
The purpose of the script is to change the files to read-only and then compress those files. I’d like to be able to select multiple files in file explorer then right-click, send to (Script)
Is this something that is possible? Thanks!
Update 1
Alright, I have it were it will select files using file explorer then pass them into the script. The read-only is functioning correctly. Just need to sort out the compression.
Add-Type -AssemblyName System.Windows.Forms
$FileBrowser = New-Object System.Windows.Forms.OpenFileDialog -Property #{
Multiselect = $true # Multiple files can be chosen
Filter = 'Images (*.jpg, *.png)|*.jpg;*.png' # Specified file types
}
[void]$FileBrowser.ShowDialog()
$path = $FileBrowser.FileNames;
If($FileBrowser.FileNames -like "*\*") {
# Do something before work on individual files commences
$FileBrowser.FileNames #Lists selected files (optional)
foreach($file in Get-ChildItem $path){
Get-ChildItem ($file) |
ForEach-Object {
Set-ItemProperty -Path $path -Name IsReadOnly -Value $true
}
}
# Do something when work on individual files is complete
}
else {
Write-Host "Cancelled by user"
}
Update 2 Alrighty I got it all working, does what I need it too. Here it is if anyone has any interest in it.
Add-Type -AssemblyName System.Windows.Forms
$FileBrowser = New-Object System.Windows.Forms.OpenFileDialog -Property #{
Multiselect = $true # Multiple files can be chosen
}
[void]$FileBrowser.ShowDialog()
$path = $FileBrowser.FileNames;
If($FileBrowser.FileNames -like "*\*") {
# Do something before work on individual files commences
$FileBrowser.FileNames #Lists selected files (optional)
foreach($file in Get-ChildItem $path){
Get-ChildItem ($file) |
ForEach-Object {
Set-ItemProperty -Path $path -Name IsReadOnly -Value $true
compact /C $_.FullName
}
}
# Do something when work on individual files is complete
}
else {
Write-Host "Cancelled by user"
}
Related
The script below uses Outlook to send emails with .docx attachments.
I would like to change the PowerShell script below to also add any .html files it finds, in addition to .docx files.
Any assistance in modifying this script is appreciated.
I would like to modify this PowerShell email script which uses Outlook so send an email with an attachment.
I want to include any .html files it also sees, in addition to the .docx file.
Thanks in advance to who may be able to assist me modify this.
#SendEMail $SendTo $MailSubject $htmlOutput
# Check to see we have all the arguments
If (Test-Path -Path "C:\Users\User1\Report\Report.html") {
$FullPath=$args[0]
#Get an Outlook application object
$o = New-Object -com Outlook.Application
$mail = $o.CreateItem(0)
#2 = High importance message
$mail.importance = 1
$mail.subject = "Report: $(get-date)"
$mail.HTMLBody = "Report $(get-date)`n$(Get-Content 'C:\Users\User1\Report\Report.html'
| Out-String)"
$mail.To = "email#emaildomain.com"
# Iterate over all files and only add the ones that have an .docx extension
$files = Get-ChildItem $FullPath
for ($i=0; $i -lt $files.Count; $i++) {
$outfileName = $files[$i].FullName
$outfileNameExtension = $files[$i].Extension
# if the extension is the one we want, add to attachments
if($outfileNameExtension -eq '.docx')
{
$mail.Attachments.Add($outfileName);
}
}
$mail.Send()
# give time to send the email
Start-Sleep 5
# quit Outlook
$o.Quit()
#end the script
#exit
}
It is not clear if also files from any subdirectories should be attached or not, but here's code for both scenarios:
Scenario 1: Only files from $FullPath, not from any subdirectories
# Iterate over all files and only add the ones that have a .docx or .html extension
$files = Get-ChildItem -Path $FullPath -File | Where-Object { '.docx', '.html' -contains $_.Extension }
foreach ($file in $files) {
$mail.Attachments.Add($file.FullName);
}
Scenario 2: All .docx and .html files from $FullPath AND its subdirectories
# Iterate over all files and only add the ones that have a .docx or .html extension
$files = Get-ChildItem -Path $FullPath -File -Recurse -Include '*.docx', '*.html'
foreach ($file in $files) {
$mail.Attachments.Add($file.FullName);
}
After this, you can send the email.
Note To stop consuming memory, you should release the COM objects:
$o.Quit()
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($mail)
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($o)
$null = [System.GC]::Collect()
$null = [System.GC]::WaitForPendingFinalizers()
Still new to powershell and I am needing to do a security report and find all the permissions applied to all folders within a drive and then export it onto an excel document. The command I've got so far includes files but all the files are setup to inherit from the folder they are in. What im hoping to do is for it to ignore all the files that include .txt, .msg, .doc, .xlsx etc etc.
Also hoping with the groups it pulls in to use the Get-Adgroupmember on it so that I can see who is in the group and also export this to the excel file in the column next to it.
$FilePath = Get-childitem "\\C:\Downloads\TEST" -Recurse
ForEach ($File in $FilePath) {
$Acl = Get-Acl -Path $File.FullName
ForEach ($Access in $Acl.Access) {
$Properties = [ordered]#{'File Name' = $File.FullName; 'Group/User' = $Access.IdentityReference; 'Permissions' = $Access.FileSystemRights; 'Inherited' = $Access.IsInherited }
New-Object -TypeName PSObject -Property $Properties | Export-Csv "C:\Downloads\FinanceResult.csv" -append -NoTypeInformation
}
}
I am looking to find a way to compact and repair all the Access databases in a certain directory using Powershell via a script.
The VBA codes below work, but need one for Powershell:
Find all Access databases, and Compact and Repair
I am new to Powershell so will be grateful for the assistance.
Thanks
You may try this.
Add-Type -AssemblyName Microsoft.Office.Interop.Access
$rootfolder = 'c:\some\folder'
$createlog = $true # change to false if no log desired
$access = New-Object -ComObject access.application
$access.Visible = $false
$access.AutomationSecurity = 1
Get-ChildItem -Path $rootfolder -File -Filter *.accdb -Recurse -PipelineVariable file | ForEach-Object {
$newname = Join-Path $file.Directory ("{0}_compacted{1}" -f $file.BaseName,$file.Extension)
$message = #"
Current file: {0}
Output file: {1}
"# -f $file.FullName,$newname
Write-Host $message -ForegroundColor Cyan
$access.CompactRepair($file.fullname,$newname,$createlog)
}
$access.Quit()
This will output each compacted database as the name of the original file with _compacted appended to the name (before the extension.) I have tested this in every way except actually compacting databases.
Edit
Regarding your comment, a few minor changes should achieve the desired result. Keep in mind that this will put all new files in the same folder. This may not be an issue for your case but if there are duplicate file names you will have problems.
$rootfolder = 'c:\some\folder'
$destination = 'c:\some\other\folder'
$todaysdate = get-date -format '_dd_MM_yyyy'
Add-Type -AssemblyName Microsoft.Office.Interop.Access
$createlog = $true # change to false if no log desired
$access = New-Object -ComObject access.application
$access.Visible = $false
$access.AutomationSecurity = 1
Get-ChildItem -Path $rootfolder -File -Filter *.accdb -Recurse -PipelineVariable file | ForEach-Object {
$newname = Join-Path $destination ("{0}$todaysdate{1}" -f $file.BaseName,$file.Extension)
$message = #"
Current file: {0}
Output file: {1}
"# -f $file.FullName,$newname
Write-Host $message -ForegroundColor Cyan
$access.CompactRepair($file.fullname,$newname,$createlog)
}
$access.Quit()
I am trying to copy multiple excel workbooks to a single excel workbook with the below, but it is only copying 6 columns when I have 35.
#Get a list of files to copy from
$Files = GCI 'C:\Users\bob\Desktop\Und' | ?{$_.Extension -Match "xlsx?"} | select -ExpandProperty FullName
#Launch Excel, and make it do as its told (supress confirmations)
$Excel = New-Object -ComObject Excel.Application
$Excel.Visible = $True
$Excel.DisplayAlerts = $False
#Open up a new workbook
$Dest = $Excel.Workbooks.Add()
`enter code here` ForEach($File in $Files[0..4]){
$Source = $Excel.Workbooks.Open($File,$true,$true)
If(($Dest.ActiveSheet.UsedRange.Count -eq 1) -and ([String]::IsNullOrEmpty ($Dest.ActiveSheet.Range("A1").Value2))){ #If there is only 1 used cell and it is blank select A1
[void]$source.ActiveSheet.Range("A1","F$(($Source.ActiveSheet.UsedRange.Rows|Select -Last 1).Row)").Copy()
[void]$Dest.Activate()
[void]$Dest.ActiveSheet.Range("A1").Select()}
Else{ #If there is data go to the next empty row and select Column A
[void]$source.ActiveSheet.Range("A2","F$(($Source.ActiveSheet.UsedRange.Rows|Select -Last 1).Row)").Copy()
[void]$Dest.Activate()
[void]$Dest.ActiveSheet.Range ("A$(($Dest.ActiveSheet.UsedRange.Rows|Select -last 1).row+1)").Select()}
[void]$Dest.ActiveSheet.Paste()
$Source.Close()}
$Dest.SaveAs("C:\Users\bob\Desktop\Und\combo\Combined.xlsx",51)
$Dest.close()
$Excel.Quit()
A solution with the excellent PoserShell module ImportExcel (with PowerShell 5 or more)
First, install the module:
in an Administrator PowerShell console: Install-Module -Name ImportExcel
in a non Administrator PowerShell console: Install-Module -Name ImportExcel -Scope CurrentUser
Then, use the following code:
$source = 'C:\Users\bob\Desktop\Und'
$destination = 'C:\Users\bob\Desktop\Und\combo\Combined.xlsx'
$fileList = Get-ChildItem -Path $source -Filter '*.xlsx'
foreach ($file in $fileList) {
$fileContent = Import-Excel -Path $file.FullName
$excelParameters = #{
Path = $destination
WorkSheetname = 'Combined'
}
if ((Test-Path -Path $destination) -and (Import-Excel #excelParameters)) {
$excelParameters.Append = $true
}
$fileContent | Export-Excel #excelParameters
}
This code assumes that all your Excel source files have the same headers and you want all your data in the same WorkSheet. But can be adapted to support other scenarios.
I'm very new to Powershell and especially to Powershell and ZIP files. I would like to unzip a specific file from the passed zipfile. To do so I have the code below. The code below should get a *.update from the zip.
The issue I have is that the specific file is within another folder. When running the script it seems it won't look in the folder in the zip for more files.
I've tried the GetFolder on the $item and/or foreach through the $item. So far no success. Anyone an idea or an direction to look in to?
function ExtractFromZip ($File, $Destination) {
$ShellApp = new-object -com shell.application
$zipFile = $ShellApp.NameSpace($File)
foreach($item in $zipFile.Items())
{
Write-Host $item.Name
if ($item.GetFolder -ne $Null) {
Write-Host "test"
}
if ($item.Name -like "*.update") {
$ShellApp.Namespace($Destination).copyhere($item)
break;
}
}
}
Here's how you can do it natively in newer versions of Powershell:
Add-Type -Assembly System.IO.Compression.FileSystem
$zip = [IO.Compression.ZipFile]::OpenRead($sourceFile)
$zip.Entries | where {$_.Name -like '*.update'} | foreach {[System.IO.Compression.ZipFileExtensions]::ExtractToFile($_, "C:\temp\test", $true)}
$zip.Dispose()
Solved it by using the script below:
Add-Type -Path 'C:\dev\Libraries\DotNetZip\Ionic.Zip.dll'
$zip = [Ionic.Zip.ZIPFile]::Read($sourceFile)
foreach ($file in $zip.Entries) {
if ($file -like "*.update") {
$zip | %{$file.Extract("C:\temp\test", [Ionic.Zip.ExtractExistingFileAction]::OverWriteSilently)}
}
}