Converting pptx file to pdf using powershell - powershell

I am trying to convert .pptx file to .pdf using powershell. I have used below code
write-host "Converting pptx to pdf....." -ForegroundColor Green
$ppt = New-Object -com powerpoint.application
$opt = [Microsoft.Office.Interop.PowerPoint.PpSaveAsFileType]::ppSaveAsPDF
$ifile = $file.FullName
$pres = $ppt.Presentations.Open($ifile)
$pathname = split-path $ifile $filename = Split-Path $ifile -Leaf
$file = $filename.split(".")[0]
$ofile = $pathname + "\" + $file + ".pdf"
$pres.SaveAs($ofile, $opt)
While running the code, i am getting error as:
Error HRESULT E_FAIL has been returned from a call to a COM component.
Any help would be highly appreciated

$pptx = "C:\test\test.pptx"
$pdf = "C:\test\test.pdf"
$ppt = New-Object -ComObject PowerPoint.Application
$ppt.Visible = $True
$presentation = $ppt.Presentations.Open($pptx)
$presentation.SaveAs($pdf, [Microsoft.Office.Interop.PowerPoint.PpSaveAsFileType]::ppSaveAsPDF)
$presentation.Close()
$ppt.Quit()

Related

Add an image to Word using PowerShell

As stated in the Title, I would like to add an image into a Word document. Though my goal is to NOT use a path (stating where the image is located).
**Like this: **
$word = New-Object -ComObject Word.Application
$word.visible = $true
$document = $word.documents.Add()
$selection = $word.selection
$newInlineShape = $selection.InlineShapes.AddPicture($path)
But rather using some type of Base64String, so that this skript works with every device, regardless if the image path doesn't exist.
My attempt:
$word = New-Object -ComObject Word.Application
$word.visible = $true
$document = $word.documents.Add()
$selection = $word.selection
$base64ImageString = [Convert]::ToBase64String((Get-Content $path -encoding byte))
$imageBytes = [Convert]::FromBase64String($base64ImageString)
$ms = New-Object IO.MemoryStream($imageBytes, 0, $imageBytes.Length)
$ms.Write($imageBytes, 0, $imageBytes.Length);
$alkanelogo = [System.Drawing.Image]::FromStream($ms, $true)
$pictureBox = new-object Windows.Forms.PictureBox
$pictureBox.Width = $alkanelogo.Size.Width;
$pictureBox.Height = $alkanelogo.Size.Height;
$pictureBox.Location = New-Object System.Drawing.Size(153,223)
$pictureBox.Image = $alkanelogo;
$newInlineShape = $selection.InlineShapes.AddPicture($pictureBox.Image)
Note: The variable "$path" is only here as a placeholder
I've figured it out. I downloaded the image to my local computer, converted it to a base64 string and then back to an image.
So that this script works with every user regardless of there path, I built in it to download the file to a specific path (that I created).
Powershell will then extract the image from the path I created.
$filepath = 'C:\temp\image.png'
$folderpath = 'C:\temp\'
if([System.IO.File]::Exists($filepath -or $folderpath)){
rmdir 'C:\temp\image.png'
$b64 = "AAA..."
$bytes = [Convert]::FromBase64String($b64)
[IO.File]::WriteAllBytes($filepath, $bytes)
}else{
mkdir 'C:\temp\' -ErrorAction SilentlyContinue
$b64 = "AAA..."
$bytes = [Convert]::FromBase64String($b64)
[IO.File]::WriteAllBytes($filepath, $bytes)
}

How to search in PDF files and move them using powershell

I have a large number of PDF files in a folder with several subfolders. In this pile of files I need to find the ones with a specific string and move them to a new destination.
I already have a fine piece of code for the search process that gives me the files needed (thx to the creator) - now I need help to combine this code with a move-function. All the files found by the following code should be moved to a new destination.
$searchString = "text i need to find"
$searchPath = "C:\test"
$sql = "SELECT System.ItemPathDisplay, System.DateModified, "
+ "System.Size, System.FileExtension FROM SYSTEMINDEX "
+ "WHERE SCOPE = '$searchPath' AND FREETEXT('$searchstring')"
$provider = "provider=search.collatordso;extended properties=’application=windows’;"
$connector = new-object system.data.oledb.oledbdataadapter -argument $sql, $provider
$dataset = new-object system.data.dataset
if ($connector.fill($dataset)) { $dataset.tables[0] }
The output is like:
SYSTEM.ITEMPATHDISPLAY SYSTEM.DATEMODIFIED SYSTEM.SIZE SYSTEM.FILEEXTENSION
---------------------- ------------------- ----------- --------------------
C:\test\file.pdf 27.08.2019 19:14:57 17119 .pdf
Thank you for your help!
I found a solution by myself. For anyone interested.
Note: $searchPath must be a local drive on the machine you are running the script on, because the PDF files need to be indexed by the windows search. For that you probably have to install an iFilter: https://superuser.com/questions/402673/how-to-search-inside-pdfs-with-windows-search
$searchString = "Merkblatt für nüchtern eintretende Patienten"
$searchPath = "Y:\"
$targetPath = "\\Server\Path\folder"
$sql = "SELECT System.ItemPathDisplay, System.DateModified, " +
"System.Size, System.FileExtension FROM SYSTEMINDEX " +
"WHERE SCOPE = '$searchPath' AND FREETEXT('$searchstring')"
$provider = "provider=search.collatordso;extended properties=’application=windows’;"
$connector = new-object system.data.oledb.oledbdataadapter -argument $sql, $provider
$dataset = new-object system.data.dataset
if ($connector.fill($dataset)) {
#$dataset.tables[0]
foreach ( $Row in $dataset.tables[0].Rows) {
$targetFile = $Row[0] -replace "^Y:", $targetPath
$targetSubfolder = Split-Path -Path $targetFile
#write-host "Targetfile : $targetFile"
#write-host "Moving: $($Row[0])"
Move-Item -Path $($Row[0]) -Destination $targetPath -Force
}
}

Powershell unzip stream

Is there a built-in cmdlet or some composition thereof that would allow me to start unzipping a file stream as each chunk is downloaded? I have a PowerShell script that needs to download a large (10 GB) file, and I have to wait until it is done right now before it starts expanding...
$wc = New-Object net.webclient
$wc.Downloadfile($appDataSnapshotUri, "%DataSnapshotFileName%.zip") # this can take some time
Expand-Archive -Path "%DataSnapshotFileName%.zip" -DestinationPath Run # so can this
OK, turns out zip file doesn't need to be fully downloaded to be decompressed, you can compress/decompress streams. There is some built in capabilities in .Net for stream compression, but it will not work with zip archives. You can use SharpZipLib library for that:
Download .nupckg from https://www.nuget.org/packages/SharpZipLib/
Extract files to any folder. You'll need ICSharpCode.SharpZipLib.dll from lib/net45
Below is my simplified translation of their example:
https://github.com/icsharpcode/SharpZipLib/wiki/Zip-Samples#unpack-a-zip-using-zipinputstream-eg-for-unseekable-input-streams
Add-Type -Path ".\ICSharpCode.SharpZipLib.dll"
$outFolder = ".\unzip"
$wc = [System.Net.WebClient]::new()
$zipStream = $wc.OpenRead("http://gitlab/test/test1/raw/master/sample.zip")
$zipInputStream = [ICSharpCode.SharpZipLib.Zip.ZipInputStream]::New($zipStream)
$zipEntry = $zipInputStream.GetNextEntry()
$fileName = $zipEntry.Name
$buffer = New-Object byte[] 4096
$sw = [System.IO.File]::Create("$outFolder\$fileName")
[ICSharpCode.SharpZipLib.Core.StreamUtils]::Copy($zipInputStream, $sw, $buffer)
$sw.Close()
It will only extract first entry, you can add a while loop it this sample works.
Here is a snippet with while loop to extract multiple files (put it after $zipEntry = $zipInputStream.GetNextEntry() on the example above):
While($zipEntry) {
$fileName = $zipEntry.Name
Write-Host $fileName
$buffer = New-Object byte[] 4096
$sw = [System.IO.File]::Create("$outFolder\$fileName")
[ICSharpCode.SharpZipLib.Core.StreamUtils]::Copy($zipInputStream, $sw, $buffer)
$sw.Close()
$zipEntry = $zipInputStream.GetNextEntry()
}
Edit
Here is what I found to work...
Add-Type -Path ".\ICSharpCode.SharpZipLib.dll"
$outFolder = "unzip"
$wc = [System.Net.WebClient]::new()
$zipStream = $wc.OpenRead("https://github.com/Esri/file-geodatabase-api/raw/master/FileGDB_API_1.5/FileGDB_API_1_5_VS2015.zip")
$zipInputStream = [ICSharpCode.SharpZipLib.Zip.ZipInputStream]::New($zipStream)
$zipEntry = $zipInputStream.GetNextEntry()
while($zipEntry) {
if (-Not($zipEntry.IsDirectory)) {
$fileName = $zipEntry.Name
$buffer = New-Object byte[] 4096
$filePath = "$pwd\$outFolder\$fileName"
$parentPath = "$filePath\.."
Write-Host $parentPath
if (-Not (Test-Path $parentPath)) {
New-Item -ItemType Directory $parentPath
}
$sw = [System.IO.File]::Create("$pwd\$outFolder\$fileName")
[ICSharpCode.SharpZipLib.Core.StreamUtils]::Copy($zipInputStream, $sw, $buffer)
$sw.Close()
}
$zipEntry = $zipInputStream.GetNextEntry()
}
To expand on Mike Twc's answer, a script to do it with and without stream, and compare how long it takes:
$url = "yoururlhere"
function UnzipStream () {
Write-Host "unzipping via stream"
$stopwatch1 = [system.diagnostics.stopwatch]::StartNew()
Add-Type -Path ".\ICSharpCode.SharpZipLib.dll"
$outFolder = "unzip-stream"
$wc = [System.Net.WebClient]::new()
$zipStream = $wc.OpenRead($url)
$zipInputStream = [ICSharpCode.SharpZipLib.Zip.ZipInputStream]::New($zipStream)
$zipEntry = $zipInputStream.GetNextEntry()
while($zipEntry) {
if (-Not($zipEntry.IsDirectory)) {
$fileName = $zipEntry.Name
$buffer = New-Object byte[] 4096
$filePath = "$pwd\$outFolder\$fileName"
$parentPath = "$filePath\.."
Write-Host $parentPath
if (-Not (Test-Path $parentPath)) {
New-Item -ItemType Directory $parentPath
}
$sw = [System.IO.File]::Create("$pwd\$outFolder\$fileName")
[ICSharpCode.SharpZipLib.Core.StreamUtils]::Copy($zipInputStream, $sw, $buffer)
$sw.Close()
}
$zipEntry = $zipInputStream.GetNextEntry()
}
$stopwatch1.Stop()
Write-Host "extraction took $($stopWatch1.ElapsedMilliseconds) millis with stream"
}
function UnzipWithoutStream() {
Write-Host "Extracting without stream"
$stopwatch2 = [system.diagnostics.stopwatch]::StartNew()
$outFolder2 = "unzip-normal"
$wc2 = New-Object System.Net.WebClient
$wc2.DownloadFile($url, "$pwd\download.zip")
$of2 = New-Item -ItemType Directory $outFolder2
Expand-Archive -Path "download.zip" -DestinationPath $of2.FullName
$stopwatch2.Stop()
Write-Host "extraction took $($stopWatch2.ElapsedMilliseconds) millis without stream"
}
UnzipStream
UnzipWithoutStream

How to create directories from powershell on FTP server?

I want to run a PS script when I want to publish to FTP server. I took this script as structure : structure script.
I have very simple folder :
C:\Uploadftp\Files\doc.txt
C:\Uploadftp\Files\Files2
C:\Uploadftp\Files\Files2\doc2.txt
nothing fancy there.
Here is my script :
cd C:\Uploadftp
$location = Get-Location
"We are here: $location"
$user = "test" # Change
$pass = "test" # Change
## Get files
$files = Get-ChildItem -recurse
## Get ftp object
$ftp_client = New-Object System.Net.WebClient
$ftp_client.Credentials = New-Object System.Net.NetworkCredential($user,$pass)
$ftp_address = "ftp://test/TestFolder"
## Make uploads
foreach($file in $files)
{
$directory = "";
$source = $($file.DirectoryName + "/" + $file);
if ($file.DirectoryName.Length -gt 0)
{
$directory = $file.DirectoryName.Replace($location,"")
}
$directory = $directory.Replace("\","/")
$source = $source.Replace("\","/")
$directory += "/";
$ftp_command = $($ftp_address + $directory + $file)
# Write-Host $source
$uri = New-Object System.Uri($ftp_command)
"Command is " + $uri + " file is $source"
$ftp_client.UploadFile($uri, $source)
}
I keep getting this error :
Exception calling "UploadFile" with "2" argument(s): "An exception occurred during a WebClient request."
If I hardcode specific folder for $uri and tell source to be some specific folder on my computer, this script doesn't create directory, it creates a file. What am I doing wrong?
P.S. dont hit me too hard, its my fist time ever doing something in power shell.
Try the "Create-FtpDirectory" function from https://github.com/stej/PoshSupport/blob/master/Ftp.psm1
function Create-FtpDirectory {
param(
[Parameter(Mandatory=$true)]
[string]
$sourceuri,
[Parameter(Mandatory=$true)]
[string]
$username,
[Parameter(Mandatory=$true)]
[string]
$password
)
if ($sourceUri -match '\\$|\\\w+$') { throw 'sourceuri should end with a file name' }
$ftprequest = [System.Net.FtpWebRequest]::Create($sourceuri);
$ftprequest.Method = [System.Net.WebRequestMethods+Ftp]::MakeDirectory
$ftprequest.UseBinary = $true
$ftprequest.Credentials = New-Object System.Net.NetworkCredential($username,$password)
$response = $ftprequest.GetResponse();
Write-Host Upload File Complete, status $response.StatusDescription
$response.Close();
}

Need help figuring out why Powershell is throwing error 16

I posted this script the other day in an effort to discover a good way to change file extensions when "saving as." I had the problem licked, but as of this morning, the script will not run without errors. Here's the error message I'm getting:
Processing : C:\users\xxx\Desktop\ht\Automatic_Post-Call_Survey.htm
Exception calling "SaveAs" with "16" argument(s): "This is not a valid file name.
Try one or more of the following:
* Check the path to make sure it was typed correctly.
* Select a file from the list of files and folders."
At C:\users\xxx\Desktop\hd.ps1:11 char:20
+ $opendoc.saveas <<<< ([ref]"$docpath\$doc.FullName.doc", [ref]$saveFormat);
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
if "16" is the error code, that represents an inability to delete the directory...but it doesn't appear as if I'm asking for that at all--unless there's some default parameter in place somewhere. I'm pretty much baffled.anyone have any other ideas I can try out?
$docpath = "c:\users\xxx\desktop\do"
$htmPath = "c:\users\xxx\desktop\ht"
$srcfiles = Get-ChildItem $htmPath -filter "*.htm*"
$saveFormat = [Enum]::Parse([Microsoft.Office.Interop.Word.WdSaveFormat], "wdFormatDocument");
$word = new-object -comobject word.application
$word.Visible = $False
$filename = ($_.fullname).substring(0,($_.FullName).lastindexOf("."))
function saveas-document {
$opendoc = $word.documents.open($doc.FullName);
$opendoc.saveas([ref]"$docpath\$filename", [ref]$saveFormat);
$opendoc.close();
}
ForEach ($doc in $srcfiles) {
Write-Host "Processing :" $doc.FullName
saveas-document
$doc = $null
}
$word.quit();
this should do what do you need, but is not the best design :)
$docpath = "c:\users\xxx\desktop\do"
$htmPath = "c:\users\xxx\desktop\ht"
$srcfiles = Get-ChildItem $htmPath -filter "*.htm*"
$saveFormat = [Enum]::Parse([Microsoft.Office.Interop.Word.WdSaveFormat], "wdFormatDocument");
$global:word = new-object -comobject word.application
$word.Visible = $False
#$filename = ($_.fullname).substring(0,($_.FullName).lastindexOf("."))
function saveas-document ($docs) {
$opendoc = $word.documents.open($docs);
$savepath = $docs -replace [regex]::escape($htmPath),"$docpath"
$savepath = $savepath -replace '\.html*', '.doc'
$opendoc.saveas([ref]"$savepath", [ref]$saveFormat);
$opendoc.close();
}
ForEach ($doc in $srcfiles) {
Write-Host "Processing :" $doc.FullName
saveas-document -doc $doc.FullName
$doc = $null
}
$word.quit();