PowerPoint to PDF: Minimum size option - vba

I was attempting to convert PowerPoint files to PDF using PowerShell and was able to do so. However, I am trying to take this one step further and select the 'Minimum Size (publishing online)' option through the script.
Is there a property that needs to be set for this to happen? I'm guessing it is the $ppQualityStandard variable but not exactly sure.
EDIT: This is what I am using currently:
function ppt_to_pdf ($folderpath, $pptname) {
Add-Type -AssemblyName office
$ppFormatPDF = 2
$ppQualityStandard = 0
$p = New-Object -ComObject PowerPoint.Application
$p.Visible = [Microsoft.Office.Core.MsoTriState]::msoTrue
$ppt = $p.Presentations.Open("$folderpath\$pptname")
$ppt.SaveCopyAs("$folderpath\$pptname", 32)
$ppt.Close()
$p.Quit()
$p = $null
[gc]::collect()
[gc]::WaitForPendingFinalizers()
}

I suspect you need to use .ExportAsFixedFormat rather than .SaveCopyAs.
It takes, among other parameters, Intent as type ppFixedFormatIntent, which can be either:
ppFixedFormatIntentScreen (=1)
or
ppFixedFormatIntentPrint (=2)
There's a host of other parms. To learn more, start PPT, go into the VBA IDE and press F2 for the Object Browser and search for ExportAsFixedFormat

Related

Powershell Excel - Using new range for search gives errors for old range

I am a complete beginner to Microsoft PowerShell, but I have worked with C++, Java, and C#. I was working on this small script for my job, and I came across a strange issue that is likely due to me not properly understanding how ranges work. This script is supposed to open up an Excel workbook, search each sheet for a name, and give the names that match along with their information. The problem is when I set the range again to search for the starting column index of information (in this case, the column to the right of the column labeled "Description"), it breaks the range when it searches for more than one match of the same last name.
I have a do-while loop that uses worksheet.range.entirerow.findnext() so that I can find multiple with the same last name. This works until I used a new range, worksheet.range.entirecolumn.find(). This is my latest code of what I tried, but I have already tried hardcoding $Range to 5 (which worked, but I want it to be dynamic) or used a new variable $RowRange (which didn't fix the issue). If I understood correctly, the range is like the current selection of two or more cells, so why can I not reset it or use a new variable? It does not loop, so I only keep finding the first name in each sheet.
P.S. As a side question, I had an issue of shutting down the process of this excel document I want to open in the background without shutting down other Excel workbooks. For some reason, using Get-Process EXCEL | Stop-Process -Force; shuts down ALL of my open workbooks. I commented it out, but I'm worried about the process not quite ending when it's done executing this code.
# Prepare output file for results
$FileName = "TEST";
$OutputFile = "Results.txt";
Remove-Item $OutputFile;
New-Item $OutputFile -ItemType file;
$Writer = [System.IO.StreamWriter] $OutputFile;
Clear-Host
Write-Host Starting...
# Start up Excel
$Excel = New-Object -ComObject Excel.Application;
$File = $FileName + ".xlsx";
# Prompt user for last name of person to search for (and write to the Results.txt output file)
Clear-Host
Write-Host Search for users in each region by their last name.
$SearchLastName = Read-Host -Prompt "Please input the person's last name";
Write-Host Searching for person...;
$Writer.WriteLine("Name Search: " + $SearchLastName);
$Writer.WriteLine("");
# Then open it without it being made visible to the user
$Excel.Visible = $false;
$Excel.DisplayAlerts = $true;
$Excel.Workbooks.Open($File);
# For each worksheet, or tab, search for the name in the first column (last names)
$Excel.Worksheets | ForEach-Object{
$_.activate();
$Range = $_.Range("A1").EntireColumn;
# Note: To search for text in the ENTIRETY of a cell, need to use the find method's lookat
# parameter (use 1). Otherwise, if searching for Smith, Nesmith also gets detected.
$SearchLast = $Range.find($SearchLastName,[Type]::Missing,[Type]::Missing,1);
$Writer.WriteLine($_.name + ": ");
if ($SearchLast -ne $null) {
$FirstRow = $SearchLast.Row;
do {
# If a first name was found, get the first name too
$FirstName = $_.Cells.Item($SearchLast.Row, $SearchLast.Column + 1).value();
# Then display in proper order
$Writer.WriteLine(" " + $SearchLast.value() + "," + $FirstName);
# From here, find the relevant information on that person
# Search for the column labeled "Description", the starting column is the next one, ending column is the number of used columns
$BeginCol = $_.Range("A1").EntireRow.find("Description",[Type]::Missing,[Type]::Missing,1).Column + 1;
$MaxColumns = $_.UsedRange.Columns.Count;
# Check each column for relevant information. If there are no extra rows after "Description" just skip
for ($i = $BeginCol; $i -le $MaxColumns; $i++) {
# The information of the current cell, found by the row of the name and the current row
$CurrentCell = $_.Cells.Item($SearchLast.Row, $i);
# Only add the description if it exists.
if (!([string]::IsNullOrEmpty($CurrentCell.value2))) {
$Description = $_.Cells.Item(1,$i).text();
# Concatenate the description with it's information.
$Display = " - (" + $Description + ": " + $CurrentCell.text() + ")";
# Display the information
$Writer.WriteLine($Display);
}
}
$Writer.WriteLine("");
# Keep searching that name in the current workbook until it finds no more
$SearchLast = $Range.FindNext($SearchLast);
} while (($SearchLast -ne $null) -and ($SearchLast.Row -ne $FirstRow));
} else {
$Writer.WriteLine("Not Found");
}
$Writer.WriteLine("");
};
# Cleaning up the environment
$Writer.close();
$Excel.Workbooks.Item($FileName).close();
$Excel.Quit();
# Force quit the Excel process after quitting
# Get-Process EXCEL | Stop-Process -Force;
# Then remove the $Excel com object to ready it for garbage collection
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($Excel);
# Then, open up the Results.txt file
Invoke-Item Results.txt;

StreamWriter cannot call a method on a null-valued expression

First time user, looking for help with a script that's been driving me crazy.
Basically, I need to create a set number of files of an exact size (512KB, 2MB, 1GB) to test a SAN. These files need to be filled with random text so that the SAN doesn't catch the nuls and does actually allocate the blocks - that's also the reason I couldn't just use fsutils.
Now, I've been messing with the new-bigrandomfile by Verboon and tweaking it to my needs.
However I'm getting the error:
You cannot call a method on a null-valued expression.
At L:\random5.ps1:34 char:9
+ $stream.Write($longstring)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
This is the bit of code I've come up with so far; I'll add a loop at the end to copy the file I just created N times so to fill up the lun.
Set-Strictmode -Version 2.0
#temp file
$file = "c:\temp\temp.rnd"
#charset size
$charset = 64
#Block Size
$blocksize = 512
#page size
$Pagesize = 512KB
#Number of blocks in a page
$blocknum = $Pagesize / $blocksize
#Resulting/desired test file size
$filesize = 1GB
#number of pages in a file
$pagenum = $filesize / $Pagesize
# create the stream writer
$stream = System.IO.StreamWriter $file
# get a 64 element Char[]; I added the - and _ to have 64 chars
[char[]]$chars = 'azertyuiopqsdfghjklmwxcvbnAZERTYUIOPQSDFGHJKLMWXCVBN0123456789-_'
1..$Pagenum | ForEach-Object {
# get a page's worth of blocks
1..$blocknum| ForEach-Object {
# randomize all chars and...
$rndChars = $chars | Get-Random -Count $chars.Count
# ...join them in a string
$string = -join $rndChars
# repeat random string N times to get a full block string length
$longstring = $string * ($blocksize / $charset)
# write 1 block to file
$stream.Write($longstring)
# release resources by clearing string variables
Clear-Variable string, longstring
}
}
$stream.Close()
$stream.Dispose()
# release resources through garbage collection
[GC]::Collect()
$file.Close()
I've tried a gazillion variants like:
$stream = [System.IO.StreamWriter] $file
$stream = System.IO.StreamWriter $file
$stream = NewObject System.IO.StreamWriter $file
Of course, being a total noob at powershell, I've tried using quotes, brackets, provided the full path instead of the variable, etc. All (or most) seem to be valid syntax variants, according to a ton of examples I found online, but the output is still the same.
In case you have any improvement to suggest or alternative way to perform this task I'm all ears.
Edited the script above: just a couple of " for $file made the error disappear, - thanks LinuxDisciple; however, the file gets created but stays at 0 bytes and the script stuck in a loop.
Fix your instantiation of StreamWriter to any of these correct variants:
$stream = [System.IO.StreamWriter]::new($file)
$stream = [IO.StreamWriter]::new($file) # the default namespace may be omitted
$stream = New-Object System.IO.StreamWriter $file
You can specify encoding:
$stream = [IO.StreamWriter]::new(
$file,
$false, # don't append
[Text.Encoding]::ASCII
)
See StreamWriter on MSDN for available constructors and parameters.
PowerShell ISE offers autocomplete with tooltips:
type [streamw and press Ctrl-Space to autocomplete the full .NET class name
type ]:: to see the available methods and properties
type new and press Ctrl-Space to see the constructor overrides
whenever needed, put the caret at the method name and press Ctrl-Space for the tooltip
I know nothing about powershell but a few things:
Are you sure $longstring has a value before you call stream.Write()? It sounds like it's null and that's why the error. If you can somehow output the value of $longstring to the console, it would help you make sure that it has a value.
Also, troubleshoot the code with a simplified version of your code, so that you can pinpoint what's going on, for example
$file = c:\temp\temp.rnd
$stream = System.IO.StreamWriter $file
$longstring = 'whatever'
$stream.Write($longstring)

Copying Text File Data into existing Excel Workbook Using PowerShell

So I'm having a problem exporting data from a Text.File into a Excel Workbook that contains data from a month. What ends up happening is, the code opens a new workbook with the name and tittle of the sheet called 'Geraldine3-16-2016', I don't mind that, however it never gets added or copied to the the main workbook. So eventually, the only thing that changes in the main workbook is that a new sheet gets created called 'Sheet 1'but there is no data from the text file. Any help is greatly appreciated, Thank you in advance!
function Release-Ref ($ref) {
([System.Runtime.InteropServices.Marshal]::ReleaseComObject(
[System.__ComObject]$ref) -gt 0)
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
}
$File='C:\users\cesar.sanchez\downloads\Returns data 2-16-15.xlsx'
$TextFile='C:\Users\cesar.sanchez\downloads\Geraldine3-16-2016.txt'
$Excel = New-Object -C Excel.Application
$Excel.Visible=$true #For troubleshooting purposes only.
# $Excel.DisplayAlerts = $false
$TextData = $Excel.Workbooks.Opentext($TextFile,$null,$true)
$ExcelData = $Excel.Workbooks.Open($File) # Open Template
$NewS_ExcelData=$ExcelData.sheets.add()
$TexttoCopy=$TextData.Sheets.item(1)
$TexttoCopy.copy($NewS_ExcelData)
I believe it has to do with something in this part of the code but I'm not completely sure.
$NewS_ExcelData=$ExcelData.sheets.add()
$TexttoCopy=$TextData.Sheets.item(1)
$TexttoCopy.copy($NewS_ExcelData)
.OpenText is not the same as .Open. It does not return an object. (found out the hard way!)
$TexttoCopy=$TextData.Sheets.item(1) throws the error:
You cannot call a method on a null-valued expression.
Alternative code:
$File='C:\users\cesar.sanchez\downloads\Returns data 2-16-15.xlsx'
$TextFile='C:\Users\cesar.sanchez\downloads\Geraldine3-16-2016.txt'
$Excel = New-Object -C Excel.Application
$Excel.Visible=$true #For troubleshooting purposes only.
# $Excel.DisplayAlerts = $false
$Excel.Workbooks.Opentext($TextFile,$null,$true) # Open Text file
$TextData = $Excel.ActiveWorkbook # Assign active workbook
$ExcelData = $Excel.Workbooks.Open($File) # Open Template
$NewS_ExcelData = $ExcelData.sheets.add()
$TexttoCopy = $TextData.Sheets.item(1)
$TexttoCopy.copy($NewS_ExcelData)
You may also find $TexttoCopy.move($NewS_ExcelData) useful.

Powershell Pull Current OU

I need to be able to pull the current machine OU. I found some VB code that could do this,but I would like to just be able to do in the script with out having to call VB. Any ideas, the VB code is below.
Set objSysInfo = CreateObject("ADSystemInfo")
DN = objSysInfo.ComputerName
WScript.Echo DN
-Josh
You can get the ADSystemInfo with this function.
function Get-LocalLogonInformation
{
try
{
$ADSystemInfo = New-Object -ComObject ADSystemInfo
$type = $ADSystemInfo.GetType()
New-Object -TypeName PSObject -Property #{
UserDistinguishedName = $type.InvokeMember('UserName','GetProperty',$null,$ADSystemInfo,$null)
ComputerDistinguishedName = $type.InvokeMember('ComputerName','GetProperty',$null,$ADSystemInfo,$null)
SiteName = $type.InvokeMember('SiteName','GetProperty',$null,$ADSystemInfo,$null)
DomainShortName = $type.InvokeMember('DomainShortName','GetProperty',$null,$ADSystemInfo,$null)
DomainDNSName = $type.InvokeMember('DomainDNSName','GetProperty',$null,$ADSystemInfo,$null)
ForestDNSName = $type.InvokeMember('ForestDNSName','GetProperty',$null,$ADSystemInfo,$null)
PDCRoleOwnerDistinguishedName = $type.InvokeMember('PDCRoleOwner','GetProperty',$null,$ADSystemInfo,$null)
SchemaRoleOwnerDistinguishedName = $type.InvokeMember('SchemaRoleOwner','GetProperty',$null,$ADSystemInfo,$null)
IsNativeModeDomain = $type.InvokeMember('IsNativeMode','GetProperty',$null,$ADSystemInfo,$null)
}
}
catch
{
throw
}
}
You can't use ADSystemInfo directly in Powershell (or at least it's not easy) according to this page
Well, OK, that’s not entirely true; it is possible to use ADSystemInfo from within PowerShell; however, the process is far from easy and even farther from being intuitive. That’s because ADSystemInfo is lacking a “wrapper” that makes it easy to access the object from a .NET language like Windows PowerShell. That results in a lot of gyrations involving .NET Reflection classes, the InvokeMember method, and, as near as we can tell, a lot of prayer.
But the page does provide examples for performing AD queries using the System.DirectoryServices.DirectorySearcher .NET object. Here's an example from the page slightly modified to match your VB script:
$strName = $env:computername
$strFilter = "(&(objectCategory=Computer)(Name=$strName))"
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.Filter = $strFilter
$objPath = $objSearcher.FindOne()
$objPath.GetDirectoryEntry().distinguishedname

ClearCase : list the content of a directory (ls) using CAL

In ClearCase, you can list the content of a directory using "cleartool ls".
My question is how can I do the same thing using CAL (ClearCase Automation Layer). The reason I prefer the COM API is because I won't have to parse the output of "ls".
So far, I am able to get the VOB and the View successfully, but I didn't find any method for listing the content.
My code so far:
IClearCase cc = new ApplicationClass();
CCVOB vob = cc.get_VOB("\\VOB-name");
CCView view = cc.get_View("ViewTag");
Thank you for your help.
I wrote VonC's answer in C# for those interrested.
string[] files = Directory.GetFiles("View path here", "*.*", SearchOption.AllDirectories);
foreach (string file in files)
{
try
{
CCVersion ver = cc.get_Version(file);
Console.WriteLine(ver.Path);
}
catch(Exception) {/*the file is not versioned*/}
}
May be this is a good start:
Set CC = Wscript.CreateObject("ClearCase.Application")
Set DirVer = CC.Version(".")
Set FSO = CreateObject("Scripting.FileSystemObject")
Set Folder = FSO.GetFolder(DirVer.Path)
Wscript.Echo "Files under source control: "
For Each File in Folder.Files
On Error Resume Next
Set Ver = CC.Version(File.Name)
If Err.Number = 0 Then
Wscript.Echo Ver.ExtendedPath
End If
Next
The idea being to use ICCVersion methods to try accessing the version of a file. If it does not return an error, it is indeed a versioned file.
Now I know the file is versioned, how can I remove it (rmname).
Do not use RemoveVersion():
Removes irretrievably the version (equivalent to cleartool rmver)
WARNING! This is a potentially destructive operation. Because CAL does not prompt the user for input under any circumstances, there is no confirmation step when RemoveVersion is invoked. Invoking RemoveVersion is equivalent to running cleartool rmver with the -force option.
Instead use the RemoveName from the ICCElement interface.