Say foo.zip contains:
a
b
c
|- c1.exe
|- c2.dll
|- c3.dll
where a, b, c are folders.
If I
Expand-Archive .\foo.zip -DestinationPath foo
all files/folders in foo.zip are extracted.
I would like to extract only the c folder.
try this
Add-Type -Assembly System.IO.Compression.FileSystem
#extract list entries for dir myzipdir/c/ into myzipdir.zip
$zip = [IO.Compression.ZipFile]::OpenRead("c:\temp\myzipdir.zip")
$entries=$zip.Entries | where {$_.FullName -like 'myzipdir/c/*' -and $_.FullName -ne 'myzipdir/c/'}
#create dir for result of extraction
New-Item -ItemType Directory -Path "c:\temp\c" -Force
#extraction
$entries | foreach {[IO.Compression.ZipFileExtensions]::ExtractToFile( $_, "c:\temp\c\" + $_.Name) }
#free object
$zip.Dispose()
This one does not use external libraries:
$shell= New-Object -Com Shell.Application
$shell.NameSpace("$(resolve-path foo.zip)").Items() | where Name -eq "c" | ? {
$shell.NameSpace("$PWD").copyhere($_) }
Perhaps it can be simplified a bit.
Here is something that works for me. Of Course, you will need to edit the code to fit your objective
$results =#()
foreach ($p in $Path)
{
$shell = new-object -Comobject shell.application
$fileName = $p
$zip = $shell.namespace("$filename")
$Results += $zip.items()| where-object { $_.Name -like "*C*" -or $_.Name -like
"*b*" }
}
foreach($item in $Results )
{
$shell.namespace($dest).copyhere($item)
}
Related
I'm wondering if someone can help me? I've butchered a few powershell scripts I've found online that make shortcuts from $source to $destination. However, it appears to overwrite each time, and I only want it to create a .lnk on new.
The original source of the script is here and this is my current "non working" script.. I added the following, but it doesn't seem to work. I think I need to somehow get it to check the $destination and then continue if $file.lnk doesn't exist
If ($status -eq $false) {($WshShell.fso.FileExists("$Destination") + "*.lnk")
Full script:
function Create-ShortcutForEachFile {
Param(
[ValidateNotNullOrEmpty()][string]$Source,
[ValidateNotNullOrEmpty()][string]$Destination,
[switch]$Recurse
)
# set recurse if present
if ($Recurse.IsPresent) { $splat = #{ Recurse = $true } }
# Getting all the source files and source folder
$gci = gci $Source #splat
$Files = $gci | ? { !$_.PSisContainer }
$Folders = $gci | ? { $_.PsisContainer }
# Creating all the folders
if (!(Test-Path $Destination)) { mkdir $Destination -ea SilentlyContinue > $null }
$Folders | % {
$Target = $_.FullName -replace [regex]::escape($Source), $Destination
mkdir $Target -ea SilentlyContinue > $null
}
# Creating Wscript object
$WshShell = New-Object -comObject WScript.Shell
# Creating all the Links
If ($status -eq $false) {($WshShell.fso.FileExists("$Destination") + "*.lnk")
$Files | % {
$InkName = "{0}.lnk" -f $_.sBaseName
$Target = ($_.DirectoryName -replace [regex]::escape($Source), $Destination) + "\" + $InkName
$Shortcut = $WshShell.CreateShortcut($Target)
$Shortcut.TargetPath = $_.FullName
$Shortcut.Save()
}
}
}
Create-ShortcutForEachFile -Source \\myserver.domain.local\Folder1\Folder2\Test -Destination \\myserver2.domain.local\Folder1\Folder2\Test -Recurse
Hoping anyone can help me out, apologies for being a powershell/scripting noob.
My brother kindly reworked the script to suit better to my needs.
Here it is:
#################################################
<#
CREATE-SHORTCUT - creates shortcut for all files from a source folder
version : 1.0
Author :
Creation Date :
Modified Date :
#>
#------------------------------------------------------------[ variables ]----------------------------------------------------------
$sourceDir="D:\scripts\create-shortcut\source"
$targetDir="D:\scripts\create-shortcut\dest"
#-------------------------------------------------------------[ Script ]-----------------------------------------------------------
# get files/files from folder
$src_gci=Get-Childitem -path $sourceDir -Recurse
$src_files=$src_gci | ? { !$_.PSisContainer }
$src_folders=$src_gci | ? { $_.PSisContainer }
# create subfolders
$src_folders | Copy-Item -Destination { join-path $targetDir $_.Parent.FullName.Substring($sourceDir.Length) } -Force
# create shortcuts
$WshShell = New-Object -comObject WScript.Shell
$src_files | % {
$lnkName="{0}.lnk" -f $_.BaseName
$Target = ($_.DirectoryName -replace [regex]::escape($sourceDir), $targetDir) + "\" + $lnkName
$Shortcut = $WshShell.CreateShortcut($Target)
$Shortcut.TargetPath = $_.FullName
$Shortcut.Save()
# change to SourceFiles ModifiedDate #
$src_date=$_.LastWriteTime
Get-ChildItem $Target | % { $_.LastWriteTime = "$src_date" }
}
My objective is to write a powershell script that will recursively check a file server for any directories that are "x" (insert days) old or older.
I ran into a few issues initially, and I think I got most of it worked out. One of the issues I ran into was with the path limitation of 248 characters. I found a custom function that I am implementing in my code to bypass this limitation.
The end result is I would like to output the path and LastAccessTime of the folder and export the information into an easy to read csv file.
Currently everything is working properly, but for some reason I get some paths output several times (duplicates, triples, even 4 times). I just want it output once for each directory and subdirectory.
I'd appreciate any guidance I can get. Thanks in advance.
Here's my code
#Add the import and snapin in order to perform AD functions
Add-PSSnapin Quest.ActiveRoles.ADManagement -ea SilentlyContinue
Import-Module ActiveDirectory
#Clear Screen
CLS
Function Get-FolderItem
{
[cmdletbinding(DefaultParameterSetName='Filter')]
Param (
[parameter(Position=0,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
[Alias('FullName')]
[string[]]$Path = $PWD,
[parameter(ParameterSetName='Filter')]
[string[]]$Filter = '*.*',
[parameter(ParameterSetName='Exclude')]
[string[]]$ExcludeFile,
[parameter()]
[int]$MaxAge,
[parameter()]
[int]$MinAge
)
Begin
{
$params = New-Object System.Collections.Arraylist
$params.AddRange(#("/L","/S","/NJH","/BYTES","/FP","/NC","/NFL","/TS","/XJ","/R:0","/W:0"))
If ($PSBoundParameters['MaxAge'])
{
$params.Add("/MaxAge:$MaxAge") | Out-Null
}
If ($PSBoundParameters['MinAge'])
{
$params.Add("/MinAge:$MinAge") | Out-Null
}
}
Process
{
ForEach ($item in $Path)
{
Try
{
$item = (Resolve-Path -LiteralPath $item -ErrorAction Stop).ProviderPath
If (-Not (Test-Path -LiteralPath $item -Type Container -ErrorAction Stop))
{
Write-Warning ("{0} is not a directory and will be skipped" -f $item)
Return
}
If ($PSBoundParameters['ExcludeFile'])
{
$Script = "robocopy `"$item`" NULL $Filter $params /XF $($ExcludeFile -join ',')"
}
Else
{
$Script = "robocopy `"$item`" NULL $Filter $params"
}
Write-Verbose ("Scanning {0}" -f $item)
Invoke-Expression $Script | ForEach {
Try
{
If ($_.Trim() -match "^(?<Children>\d+)\s+(?<FullName>.*)")
{
$object = New-Object PSObject -Property #{
ParentFolder = $matches.fullname -replace '(.*\\).*','$1'
FullName = $matches.FullName
Name = $matches.fullname -replace '.*\\(.*)','$1'
}
$object.pstypenames.insert(0,'System.IO.RobocopyDirectoryInfo')
Write-Output $object
}
Else
{
Write-Verbose ("Not matched: {0}" -f $_)
}
}
Catch
{
Write-Warning ("{0}" -f $_.Exception.Message)
Return
}
}
}
Catch
{
Write-Warning ("{0}" -f $_.Exception.Message)
Return
}
}
}
}
Function ExportFolders
{
#================ Global Variables ================
#Path to folders
$Dir = "\\myFileServer\somedir\blah"
#Get all folders
$ParentDir = Get-ChildItem $Dir | Where-Object {$_.PSIsContainer -eq $True}
#Export file to our destination
$ExportedFile = "c:\temp\dirFolders.csv"
#Duration in Days+ the file hasn't triggered "LastAccessTime"
$duration = 800
$cutOffDate = (Get-Date).AddDays(-$duration)
#Used to hold our information
$results = #()
#=============== Done with Variables ===============
ForEach ($SubDir in $ParentDir)
{
$FolderPath = $SubDir.FullName
$folders = Get-ChildItem -Recurse $FolderPath -force -directory| Where-Object { ($_.LastAccessTimeUtc -le $cutOffDate)} | Select-Object FullName, LastAccessTime
ForEach ($folder in $folders)
{
$folderPath = $folder.fullname
$fixedFolderPaths = ($folderPath | Get-FolderItem).fullname
ForEach ($fixedFolderPath in $fixedFolderPaths)
{
#$fixedFolderPath
$getLastAccessTime = $(Get-Item $fixedFolderPath -force).lastaccesstime
#$getLastAccessTime
$details = #{ "Folder Path" = $fixedFolderPath; "LastAccessTime" = $getLastAccessTime}
$results += New-Object PSObject -Property $details
$results
}
}
}
}
ExportFolders
I updated my code a bit and simplified it. Here is the new code.
#Add the import and snapin in order to perform AD functions
Add-PSSnapin Quest.ActiveRoles.ADManagement -ea SilentlyContinue
Import-Module ActiveDirectory
#Clear Screen
CLS
Function ExportFolders
{
#================ Global Variables ================
#Path to user profiles in Barrington
$Dir = "\\myFileServer\somedir\blah"
#Get all user folders
$ParentDir = Get-ChildItem $Dir | Where-Object {$_.PSIsContainer -eq $True} | where {$_.GetFileSystemInfos().Count -eq 0 -or $_.GetFileSystemInfos().Count -gt 0}
#Export file to our destination
$ExportedFile = "c:\temp\dirFolders.csv"
#Duration in Days+ the file hasn't triggered "LastAccessTime"
$duration = 1
$cutOffDate = (Get-Date).AddDays(-$duration)
#Used to hold our information
$results = #()
$details = $null
#=============== Done with Variables ===============
ForEach ($SubDir in $ParentDir)
{
$FolderName = $SubDir.FullName
$FolderInfo = $(Get-Item $FolderName -force) | Select-Object FullName, LastAccessTime #| ft -HideTableHeaders
$FolderLeafs = gci -Recurse $FolderName -force -directory | Where-Object {$_.PSIsContainer -eq $True} | where {$_.GetFileSystemInfos().Count -eq 0 -or $_.GetFileSystemInfos().Count -gt 0} | Select-Object FullName, LastAccessTime #| ft -HideTableHeaders
$details = #{ "LastAccessTime" = $FolderInfo.LastAccessTime; "Folder Path" = $FolderInfo.FullName}
$results += New-Object PSObject -Property $details
ForEach ($FolderLeaf in $FolderLeafs.fullname)
{
$details = #{ "LastAccessTime" = $(Get-Item $FolderLeaf -force).LastAccessTime; "Folder Path" = $FolderLeaf}
$results += New-Object PSObject -Property $details
}
$results
}
}
ExportFolders
The FolderInfo variable is sometimes printing out multiple times, but the FolderLeaf variable is printing out once from what I can see. The problem is if I move or remove the results variable from usnder the details that print out the folderInfo, then the Parent directories don't get printed out. Only all the subdirs are shown. Also some directories are empty and don't get printed out, and I want all directories printed out including empty ones.
The updated code seems to print all directories fine, but as I mentioned I am still getting some duplicate $FolderInfo variables.
I think I have to put in a condition or something to check if it has already been processed, but I'm not sure which condition I would use to do that, so that it wouldn't print out multiple times.
In your ExportFolders you Get-ChildItem -Recurse and then loop over all of the subfolders calling Get-FolderItem. Then in Get-FolderItem you provide Robocopy with the /S flag in $params.AddRange(#("/L", "/S", "/NJH", "/BYTES", "/FP", "/NC", "/NFL", "/TS", "/XJ", "/R:0", "/W:0")) The /S flag meaning copy Subdirectories, but not empty ones. So you are recursing again. Likely you just need to remove the /S flag, so that you are doing all of your recursion in ExportFolders.
In response to the edit:
Your $results is inside of the loop. So you will have a n duplicates for the first $subdir then n-1 duplicates for the second and so forth.
ForEach ($SubDir in $ParentDir) {
#skipped code
ForEach ($FolderLeaf in $FolderLeafs.fullname) {
#skipped code
}
$results
}
should be
ForEach ($SubDir in $ParentDir) {
#skipped code
ForEach ($FolderLeaf in $FolderLeafs.fullname) {
#skipped code
}
}
$results
Im trying to iterate through multiple HTML files in multiple computers.
My code is below:
ForEach ($system in (Get-Content C:\temp\computers.txt)) {
$folder = "\\$system\c`$\ProgramData\Autodesk\AdLM\"
Get-ChildItem $folder *.html |
Foreach-Object {
$c = $_.BaseName
$html = New-Object -ComObject "HTMLFile"
$HTML.IHTMLDocument2_write($(Get-content $_.Name -Raw ))
$para1 = $HTML.getElementById('para1') | % InnerText
Add-Content -path c:\temp\results.csv "$c,$system,$para1"
}
}
I'm getting the following error:
New-Object : Cannot find parameter Raw
You can use the Internet Explorer COM object to do what you'd like the HTMLFile COM object to do. HTMLFile isn't working 100% in all versions of Powershell, so this is a viable alternative.
ForEach ($system in (Get-Content C:\temp\computers.txt)) {
$folder = "\\$system\c`$\ProgramData\Autodesk\AdLM\"
Get-ChildItem $folder *.html |
ForEach-Object {
$c = $_.BaseName
$ie=New-Object -ComObject InternetExplorer.Application
$ie.Navigate("$_")
while ($ie.busy -eq $true) {
Start-Sleep -Milliseconds 500
}
$doc=$ie.Document
$elements=$doc.GetElementByID('para1')
$elements.innerText | ForEach-Object { Add-Content -path c:\temp\results.csv "$c,$system,$para1" }
}
}
Got this script running. Nearly completed my mission to print attachments from it that land in a specific subfolder of outlook
$OutputFolder = 'C:\tests';
$outlook = New-Object -ComObject Outlook.Application;
$olFolderInbox = 6;
$ns = $outlook.GetNameSpace("MAPI");
$inbox = $ns.GetDefaultFolder($olFolderInbox);
$inbox.Folders `
| ? Name -eq 'colour' `
| % Items `
| % Attachments `
| % {
$OutputFileName = Join-Path -Path $OutputFolder -ChildPath $_.FileName;
if (Test-Path $OutputFileName) {
$FileDirectoryName = [System.IO.Path]::GetDirectoryName($OutputFileName);
$FileNameWithoutExtension = [System.IO.Path]::GetFileNameWithoutExtension($OutputFileName);
$FileExtension = [System.IO.Path]::GetExtension($OutputFileName);
for ($i = 2; Test-Path $OutputFileName; $i++) {
$OutputFileName = "{0} ({1}){2}" -f (Join-Path -Path $FileDirectoryName -ChildPath $FileNameWithoutExtension), $i, $FileExtension;
}
}
Write-Host $OutputFileName;
$_.SaveAsFile($OutputFileName)
}
Remove-Item -Path C:\tests\*.jpg
Dir C:\tests\ | Out-Printer -name xerox-b8
Remove-Item -Path C:\tests\*.*
when i try to pipe the objects to print i am getting XML printing out, or just the directory contents
I have tried:
select-object (wrong)
get-childitem (wrong)
DIR C:\tests\*.* (only returns directory listing printout)
These either return a load of XML rubbish or just a directory listing,
How can i pipe the contents of a folder to a printer using powershell, surely this can be done
I am new to Powershell and am struggling a bit. I have obtained an example of the sort of function I want to use and adapted it partially. What I want is for it to loop through each subdirectory of C:\Test\, and combine just the PDFs in each subdirectory together (leaving the resulting PDF in each subdirectory).
At the moment I can get it to comb through the subdirectories, but it then combines the contents of all subdirectories into one giant PDF in the top level directory, which is not what I want. I feel like maybe I need to use an array of sorts but I don't know Powershell well enough yet.
BTW this uses PDFSharp - a .Net library.
Function PDFCombine {
$filepath = 'C:\Test\'
$filename = '.\Combined' #<--- ???
$output = New-Object PdfSharp.Pdf.PdfDocument
$PdfReader = [PdfSharp.Pdf.IO.PdfReader]
$PdfDocumentOpenMode = [PdfSharp.Pdf.IO.PdfDocumentOpenMode]
foreach($i in (gci $filepath *.pdf -Recurse)) {
$input = New-Object PdfSharp.Pdf.PdfDocument
$input = $PdfReader::Open($i.fullname, $PdfDocumentOpenMode::Import)
$input.Pages | %{$output.AddPage($_)}
}
$output.Save($filename)
}
Your question was unclear about how many levels you need to go down. You can try this (untested). It goes one level down from $filepath, gets all pdf files in that folder and it's subfolders and combines them into Subfoldername-Combined.pdf:
Function PDFCombine {
$filepath = 'C:\Test\'
$PdfReader = [PdfSharp.Pdf.IO.PdfReader]
$PdfDocumentOpenMode = [PdfSharp.Pdf.IO.PdfDocumentOpenMode]
#Foreach subfolder(FIRST LEVEL ONLY!)
Get-ChildItem $filepath | Where-Object { $_.PSIsContainer } | Foreach-Object {
#Create new ouput pdf-file
$output = New-Object PdfSharp.Pdf.PdfDocument
$outfilepath = Join-Path $_.FullName "$($_.Name)-Combined.pdf"
#Find and add pdf files in subfolders
Get-ChildItem -Path $_.FullName -Filter *.pdf -Recurse | ForEach-Object {
#$input = New-Object PdfSharp.Pdf.PdfDocument #Don't think this one's necessary
$input = $PdfReader::Open($_.fullname, $PdfDocumentOpenMode::Import)
$input.Pages | %{ $output.AddPage($_) }
}
#Save
$output.Save($outfilepath)
}
}
So you should get this:
c:\Test\Folder1\Folder1-Combined.pdf #should include all pages in Folder1 and ANY subfolders below)
c:\Test\Folder2\Folder2-Combined.pdf #should include all pages in Folder2 and ANY subfolders below)
#etc.
If you need it to create a combined pdf for every subfolder(not only the first level), then you could try this(untested):
Function PDFCombine {
$filepath = 'C:\Test\'
$PdfReader = [PdfSharp.Pdf.IO.PdfReader]
$PdfDocumentOpenMode = [PdfSharp.Pdf.IO.PdfDocumentOpenMode]
#Foreach subfolder with pdf files
Get-ChildItem -Path $filepath -Filter *.pdf -Recurse | Group-Object DirectoryName | ForEach-Object {
#Create new ouput pdf-file
$output = New-Object PdfSharp.Pdf.PdfDocument
$outfilepath = Join-Path $_.Name "Combined.pdf"
#Find and add pdf files in subfolders
$_.Group | ForEach-Object {
#$input = New-Object PdfSharp.Pdf.PdfDocument #I don't think you need this
$input = $PdfReader::Open($_.fullname, $PdfDocumentOpenMode::Import)
$input.Pages | %{ $output.AddPage($_) }
}
#Save
$output.Save($outfilepath)
#Remove output-object
Remove-Variable output
}
}
not tested ...
Function PDFCombine {
$filepath = 'C:\Test\'
$filename = '.\Combined' #<--- ???
$output = New-Object PdfSharp.Pdf.PdfDocument
$PdfReader = [PdfSharp.Pdf.IO.PdfReader]
$PdfDocumentOpenMode = [PdfSharp.Pdf.IO.PdfDocumentOpenMode]
$lastdir=""
foreach($i in (gci $filepath *.pdf -Recurse)) {
$input = New-Object PdfSharp.Pdf.PdfDocument
$input = $PdfReader::Open($i.fullname, $PdfDocumentOpenMode::Import)
$input.Pages | %{$output.AddPage($_)}
if ($lastdir -ne $_.directoryname){
$lastdir=$_.directoryname
$output.Save("$lastdir\$filename")
$output = New-Object PdfSharp.Pdf.PdfDocument
}
}
}