How do I unzip multiple files? - powershell

I am attempting to loop through zip files in a folder and extract them. I am receiving a null error for the zip.items(). How could this value be null?
When I Write-Host $zip the value that is posted is System.__ComObject.
$dira = "D:\User1\Desktop\ZipTest\IN"
$dirb = "D:\User1\Desktop\ZipTest\DONE\"
$list = Get-childitem -recurse $dira -include *.zip
$shell = new-object -com shell.application
foreach($file in $list)
{
$zip = $shell.NameSpace($file)
foreach($item in $zip.items())
{
$shell.Namespace($dirb).copyhere($file)
}
Remove-Item $file
}
The error message I am receiving is:
You cannot call a method on a null-valued expression.
At D:\Users\lr24\Desktop\powershellunziptest2.ps1:12 char:29
+ foreach($item in $zip.items <<<< ())
+ CategoryInfo : InvalidOperation: (items:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull

$file is a FileInfo object, but the NameSpace() method expects either a string with a full path or a numeric constant. Also, you need to copy $item, not $file.
Change this:
foreach($file in $list)
{
$zip = $shell.NameSpace($file)
foreach($item in $zip.items())
{
$shell.Namespace($dirb).copyhere($file)
}
Remove-Item $file
}
into this:
foreach($file in $list)
{
$zip = $shell.NameSpace($file.FullName)
foreach($item in $zip.items())
{
$shell.Namespace($dirb).copyhere($item)
}
Remove-Item $file
}

If you have 7-zip in your $env:path
PS> $zips = dir *.zip
PS> $zips | %{7z x $_.FullName}
#unzip with Divider printed between unzip commands
PS> $zips | %{echo "`n`n======" $_.FullName; 7z x $_.FullName}
you can get 7-zip here:
http://www.7-zip.org/
PS> $env:path += ";C:\\Program Files\\7-Zip"
Explanation:
Percent followed by curly braces is called the foreach operator: %{ }
This operator means that "Foreach" object in the pipe, the code in the curly braces is called with the object placed in the "$_" variable.

You're missing the shell initialization.
$shell = new-object -com shell.application
use it before the NameSpace.

Related

Powershell/WScript Create Shortcut if not exist

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" }
}

How to find a certain phrase of doc/docx files from a folder by using powershell

Good Morning, I am very new to powershell.
I have been googling around how to find a certain phrase in .doc, .docx from some folder, but I can not find the exact solution what I am looking for.
For example, when I executed this code
Get-ChildItem 'C:\Users\koshiasu\Desktop\adhocs' -Filter *.sql |Select-String -Pattern "children"
It shows like this in the bottom of my powershell
result1
Desktop\adhocs\18722 Parents.sql:11: AND EXISTS (SELECT c.id_number FROM children c
Desktop\adhocs\18722 Parents.sql:38: AND EXISTS (SELECT c.id_number FROM children c
Desktop\adhocs\2969 ADHOC - Parents in Dallas.sql:11: AND EXISTS (SELECT c.id_number FROM children c
Desktop\adhocs\2969 ADHOC - Parents in Dallas.sql:92: AND EXISTS (SELECT c.id_number FROM children c
I would like to same thing for .doc,.docx
so I changed the code like this
Get-ChildItem 'C:\Users\koshiasu\Desktop\ADHOCS_WORD' -Filter *.doc, *.docx |Select-String -Pattern "Allocations"
but the error is
Get-ChildItem : Cannot convert 'System.Object[]' to the type 'System.String' required by parameter 'Filter'. Specified method is not supported.
At line:2 char:58
+ Get-ChildItem 'C:\Users\koshiasu\Desktop\ADHOCS_WORD' -Filter <<<< *.doc, *.docx |Select-String -Pattern "Allocations"
+ CategoryInfo : InvalidArgument: (:) [Get-ChildItem], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgument,Microsoft.PowerShell.Commands.GetChildItemCommand
how should I change the code to show like result1
Thank you so much
I had code for something basically identical lying around, tidied up slightly so you can get an idea of what you're looking for:
$Path = "C:\Test"
$Find = "Allocations"
$WordExts = '.docx','.doc','.docm'
$Word = New-Object -ComObject Word.Application #create word obj
$Word.Visible = $false #hide the window
$ValidDocs = Get-ChildItem $Path | ? {$_.Extension -in $WordExts} | ForEach { #Foreach doc/docx/docm file in the above folder
$Doc = $Word.Documents.Open($_.FullName) #Open the document in the word object
$Content = $Doc.Content #get the 'content' object from the document
$Content.MoveStart() | Out-Null #ensure we're searching from the beginning of the doc
#term,case sensitive,whole word,wildcard,soundslike,synonyms,direction,wrappingmode
if ($Content.Find.Execute($Find,$false, $true, $false, $false, $false, $true, 1)){ #execute a search
Write-Host "$($_.Name) contains $($findText)" -ForegroundColor Green
$_.FullName #store this in $ValidDocs
} else {
Write-Host "$($_.Name) does not contain $($findText)" -ForegroundColor Red
}
$Doc.Close() #close the individual document
$Doc = $null #null it just in case
}
$Word.Quit() #quit the word process
$Word = $null #null it just in case
return $ValidDocs #return list of docs with the word in them
Here is another solution how to search for a phrase inside .docx files.
$destination = 'c:\temp\'
$docs = Get-ChildItem -Path $source -Recurse | Where-Object {$_.Name -match
'.docx'}
foreach ($doc in $docs)
{
if
($word.Documents.Open($doc.FullName).Content.Find.Execute('wordtosearchfor'))
{
Write-Host "$doc contains 'Test'"
$docs | Out-File C:\temp\result.txt
}
else
{
$word.Application.ActiveDocument.Close()
}
}

Open zip files in nested directories fails with "unexpected token" error

I have a script that I am trying to get to sort through a directory and open all the zip files and store the text files all to one directory. Here is the code:
#Script to open zip files in tree
New-Item E:\Files -type directory
Get-ChildItem -Path E:\SNL_Insurance\* -Recurse -Exclude "*.md5"|
ForEach-Object {
$file = $_
write-host $file;
$destination = "E:\Files"
$shell = New-Object -com shell.application
$zip = $shell.NameSpace($file) |
foreach($item in $_.items()){
$shell.Namespace($destination).copyhere($item)
}
}
I think I almost have it, but keep getting this error (any elaboration on piping would be helpful):
Unexpected token 'in' in expression or statement.
At E:\Expand-ZIPFile.ps1:14 char:19
+ foreach($item in <<<< $_.items()){
+ CategoryInfo : ParserError: (in:String) [], ParseException
+ FullyQualifiedErrorId : UnexpectedToken
EDIT:
Ahh... thanks for that distinction. I made your edits but after each of my "write-host" checks to see the file name I get the following error:
`You cannot call a method on a null-valued expression. At E:\Expand-ZIPFile.ps1:14 char:30 + foreach($item in $zip.items <<<< ()){ + CategoryInfo : InvalidOperation: (items:String) [], RuntimeException + FullyQualifiedErrorId : InvokeMethodOnNull
EDIT2: So the original code does copy files to a new directory but also copies the whole zip file over. I tried to add an if statement to only copy files that are .txt but the code just steps through each directory without copying anything. If you have any idea that would be appreciated as I have exhausted all my ideas. Here is the code:
new-Item E:\Files -type directory
Get-Childitem -path E:\SNL_Insurance\* -recurse -exclude "*.md5" |
Foreach-object {
$file = $_
write-host $file;
$destination = "E:\Files"
$shell = new-object -com shell.application
$zip = $shell.NameSpace($file.Fullname)
foreach($item in $zip.items()){
if ($item.Extension -eq ".txt") {
$shell.Namespace($destination).copyhere($item)
}
}
}
You're confusing foreach with ForEach-Object loops. The former neither read from nor do they write to pipelines. Also, $file is a FileInfo object, not a path. The NameSpace method expects a path string, so you need to use $file.FullName.
Replace
$zip = $shell.NameSpace($file) |
foreach($item in $_.items()){
$shell.Namespace($destination).copyhere($item)
}
with
$zip = $shell.NameSpace($file.FullName)
foreach($item in $zip.items()){
$shell.Namespace($destination).copyhere($item)
}

I want to extract all .zip files in a given directory in temp using powershell

I wrote the following code for extracting the .zip files to temp:
function Expand-ZIPFile($file, $destination)
{
$shell = new-object -com shell.application
$zip = $shell.NameSpace($file)
foreach ($item in $zip.items()) {
$shell.Namespace($destination).copyhere($item)
}
}
Expand-ZIPFile -file "*.zip" -destination "C:\temp\CAP"
But I got the following error:
PS C:\Users\v-kamoti\Desktop\CAP> function Expand-ZIPFile($file, $destination)
{
$shell = new-object -com shell.application
$zip = $shell.NameSpace($file)
foreach ($item in $zip.items()) {
$shell.Namespace($destination).copyhere($item)
}
}
Expand-ZIPFile -file "*.zip" -destination "C:\temp\CAP"
You cannot call a method on a null-valued expression.
At line:5 char:19
+ foreach($item in $zip.items())
+ ~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
Get-ChildItem 'path to folder' -Filter *.zip | Expand-Archive -DestinationPath 'path to extract' -Force
requires ps v5
You can use this if you want to create a new folder for each zip file:
#input variables
$zipInputFolder = 'C:\Users\Temp\Desktop\Temp'
$zipOutPutFolder = 'C:\Users\Temp\Desktop\Temp\Unpack'
#start
$zipFiles = Get-ChildItem $zipInputFolder -Filter *.zip
foreach ($zipFile in $zipFiles) {
$zipOutPutFolderExtended = $zipOutPutFolder + "\" + $zipFile.BaseName
Expand-Archive -Path $zipFile.FullName -DestinationPath $zipOutPutFolderExtended
}
You have to provide the full path explicitly (without wildcards) in the following call:
$shell.NameSpace($file)
You could rewrite your function like this:
function Expand-ZIPFile($file, $destination)
{
$files = (Get-ChildItem $file).FullName
$shell = new-object -com shell.application
$files | %{
$zip = $shell.NameSpace($_)
foreach ($item in $zip.items()) {
$shell.Namespace($destination).copyhere($item)
}
}
}

Powershell path not taking string variable

I am using the following code to select a folder through the Windows Forms "Browse" function and then pass that path to the gci cmdlet
cls
Function Get-Directory($initialDirectory)
{
[System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") |
Out-Null
$OpenfolderDialog = New-Object System.Windows.Forms.FolderBrowserDialog
$OpenfolderDialog.RootFolder = $initialDirectory
$OpenfolderDialog.ShowDialog()| Out-Null
$StartDir = $OpenfolderDialog.SelectedPath
Return $StartDir | Out-String
}
$myDir = Get-Directory -initialDirectory "Desktop"
$Child = gci -path $mydir -r -Filter *.jpg
Foreach ($item in $Child) {Move-Item -path $item.pspath -Destination $myDir -Force}
but I get these errors:
***At C:\Test\Combine Pics2.ps1:17 char:13
+ $Child = gci <<<< -path $mydir -r -Filter *.jpg
+ CategoryInfo : ObjectNotFound: (C:\Test
:String) [Get-ChildItem], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
Move-Item : Cannot bind argument to parameter 'Path' because it is null.
At C:\Test\Combine Pics2.ps1:19 char:43
+ Foreach ($item in $Child) {Move-Item -path <<<< $item.pspath -Destination $myDir -Force}
+ CategoryInfo : InvalidData: (:) [Move-Item], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.MoveItemCommand***
The $myDir variable is of type String, why does it not pass to the -path parameter.
What if the user canceled the dialog? Give this a try:
Function Get-Directory($initialDirectory)
{
[System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null
$OpenfolderDialog = New-Object System.Windows.Forms.FolderBrowserDialog
$OpenfolderDialog.RootFolder = $initialDirectory
$result = $OpenfolderDialog.ShowDialog()
if($result -eq 'ok')
{
$OpenfolderDialog.SelectedPath
}
else
{
"canceled"
}
}
$mydir = Get-Directory -initialDirectory Desktop
if($mydir -ne 'canceled')
{
gci -path $mydir
}
Try this:
Function Get-Directory($initialDirectory)
{
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null
$OpenfolderDialog = New-Object System.Windows.Forms.FolderBrowserDialog
$OpenfolderDialog.RootFolder = $initialDirectory
if ($OpenfolderDialog.ShowDialog() -eq "OK") {
#Continue only if a folder was selected
$OpenfolderDialog.SelectedPath
}
}
$myDir = Get-Directory -initialDirectory "Desktop"
#Continue only if a folder was selected
if($myDir) {
$Child = Get-ChildItem -path $mydir -Recurse -Filter *.jpg
Foreach ($item in $Child) {
Move-Item -path $item.pspath -Destination $myDir -Force
}
}
I cleaned it up with a few if-tests so it doesn't return errors when people cancel the dialog. There was no need to Out-String as SelectedPath returns a single string by itself.
I got a newline and carriage return at the end of the $mydir value, so try trimming with something like this to see if that is your issue:
$Child = gci -path $mydir.Trim("`r`n") -r -Filter *.jpg
Update: Better yet, just lose the Out-String in your function:
Return $StartDir