I'm trying to automate opening and saving a lot of powerpoints that all have the same password. I have done this with excels already, the only point that is unclear is I couldn't find any information online about passing a password variable through presentation.open. I was able to do that with WorkBooks.open
The script looks like this"
add-type -AssemblyName microsoft.VisualBasic
add-type -AssemblyName System.Windows.Forms
$passwd = Read-Host("Type in the password:")
$objPP = new-object -comobject powerpoint.application
$objPP.visible = [Microsoft.Office.Core.MsoTriState]::msoTrue
#Paste in Path to Powerpoints
dir C:\Users\me\Desktop\cracking\*.pptx | ForEach-Object {
$doc = $objPP.presentations.open($_.FullName)
}
I'm not sure how to configure the parameter of presentation.open to pass $passwd
When I did this with excel it basically looked like this:
$doc = $objExcel.WorkBooks.Open($_.FullName,1,$false,5,"$passwd","$passwd")
Is there a way to do this with powerpoint?
OR is there a way to focus in on the password box so I can use SENDKEYs?
That may also work and I may try to go that route to do this with PDFs.
The problem I noticed is once that password box comes up my script will not continue until after I type in the password. I can't SENDKEYs to the password box.
Thanks.
The syntax for opening a password-protected presentation in VBA, assuming you know the password, is:
Presentations.Open("c:\temp\open.pptx::password::")
IIRC, no error results if you use a password on a non-passworded file; passing the wrong password results in a trappable error, so you can use that to test for password protected files even when you don't know the password ... just pass a bogus password and test for errors.
Related
so I am trying to prepare a simple robocopy script. the script will be used by almost 500 users, so I am trying to keep it as simple and as user-friendly as possible.
to collect the information such as source and destination, i wanted to have a pop up window asking users to enter the information. I checked on the other forums and here as well, so far i found several alternatives, unfortunately none of them "does the trick"
Option 1 (my favorite except PowerShell hangs when I use it):
Add-Type -AssemblyName Microsoft.VisualBasic
$title = 'Your Current File Shares (Source)'
$msg = 'Please enter the EEX file share you want to copy from ( please make sure the format is \\server\share\...) :'
$source = [Microsoft.VisualBasic.Interaction]::InputBox($msg, $title)
Add-Type -AssemblyName Microsoft.VisualBasic
$title = 'Your new drive (Destination)'
$msg = 'Please enter to where you want to copy your files (please make sure you choose the full destination) :'
$destination = [Microsoft.VisualBasic.Interaction]::InputBox($msg, $title)
Robocopy $source $Destination /log:N:\logfile.txt
Option 2 (similar to option just a different way to call VB it seems): replying the first line Add-Type -AssemblyName Microsoft.VisualBasic with [void][Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic') , doesn't make it any better .
with both 2 options above PowerShell hangs after the 3rd run. SOmetimes after the first run it hangs. Odd thing is it runs succesfully and runs the robocopy command , but then after it's done it stops responding after a few minutes. Not sure if VB is looping in the background and has to be stopped?
Option 3:
$source = Read-Host 'Enter Your current file share:' -AsSecureString
$destination = Read-Host 'Enter Your new file share:' -AsSecureString
This is simple enough, however you cannot control anything in the box, which is something we can live with, but the main issue is the secure string, so it doesn't allow the user to see what he or she is typing, which would lead to a lot of human errors.
Option 4:
function copy_files {
param (
[string]$Copy_from,
[string]$Copy_to
)
[pscustomobject]#{
copy_from = $Copy_from
copy_to = $copy_to
}
}
$result = Invoke-Expression (Show-Command Copy_files -PassThru )
$result
has a form that is really not desirable , with the "copy" in the middle on the bottom (on the bottom of the form one sees ok / copy / cancel ) which would confuse users causing to hit copy and wait for something to happen (as the purpose is to transfer files…)
another negative thing is that it is very limited in terms what text and title you can use (or at least what I can use as I tried to have spaces but it wouldn't recognize it no matter if put them in quotations or double quotations). But such cosmetic con i can live with.
I cannot add any additional modules so showui for example is unfortunately not an option.
Any ideas on how this can be done?
Thanks in advance
There are pre-built scripts for this sort of thing that you can use as-is or tweak as needed.
The AutoCopier - PowerShell File Copy Utility w/GUI
A PowerShell GUI utility to copy files to computers based on a supplied text file of Hostnames/IP addresses. Please read below for more details and feedback would be appreciated!
Download: AutoCopier.ps1
Just need a little help with a Powershell Script.
I have a last messagebox on my script. what i want to accomplish is bring the messagebox in front of all the windows.
cmdlet that i use is
$end=[system.Windows.Forms.Messagebox]::Show('StartUP Tool Progress Completed!','StartUP Warning')
Alternatively, if all you need is a message box you can use the Wscript Shell:
$wshell = New-Object -ComObject Wscript.Shell
$wshell.Popup("StartUP Tool Progress Completed",0,"Completed",0x0)
For more information: Popup Method
This is a WinForms question, more than a PowerShell question. You'll need to pass in Form.ActiveForm. Form.ActiveForm would give you the currently active form, even if you are raising your MessageBox from any other class.
However, I think you might want to look at Read-Host -AsSecureString or, more preferably, Get-Credential if the prompt is for confidential data.
Read-Host uncontrollably stops the script to prompt the user, which means that you can never have another script that includes the script that uses Read-Host.
Thankfully, PowerShell has a lot of built-in help for launching dialogs. You're trying to ask for parameters.
You should use the
[Parameter(Mandatory=$true)]
attribute, and correct typing, to ask for the parameters. Read up on "params" if you haven't already.
If you use Parameter attribute on a [SecureString], it will prompt for a password field. If you use this on a Credential type, ([Management.Automation.PSCredential]), the credentials dialog will pop up, if the parameter isn't there. A string will just become a plain old text box. If you add a HelpMessage to the parameter attribute (that is, [Parameter(Mandatory = $true, HelpMessage = 'New User Credentials')]) then it will become help text for the prompt.
Finally, you can try this dirty trick, leveraging Microsoft Visual basic DLLs:
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic') | Out-Null
$computer = [Microsoft.VisualBasic.Interaction]::InputBox("Enter a computer name", "Computer", "$env:computername")
I need to map drives and I have an encoded PW which I need to connect to DMZ drives.
I'm using the following code to map the drives:
[Byte[]]$key = (1..16)
$pw = Get-Content .\LocalAdminCred.txt | ConvertTo-SecureString -key $key
# some other stuff
[string]$pwencoded = ConvertFrom-SecureString $pw -Key $key
$Map = New-Object -comobject Wscript.Network
$Map.MapNetworkDrive($_.letter,$_.path,$false,$_.username,$pwencoded)
What your eyes catches first is the $pwencoded Variable - I had to use a string for PW, that's why I needed to decode the Secure.String to a normal string, otherwise i would have had a type mismatch. now the problem is that .MapNetworkDrive needs the password in plain text like 'password' and mine is an encoded key and not a plain text.
To the question: Is it possible to use a encrypted password or even better a secure string to map my network drive this way? I really don't want to use plain text.
First I wanted to do the mapping with New-PSDrive but since the script must work for PS 2.0 I can't use that because the -persist Parameter doesn't exist there.
I don't think this is the answer you're looking for but Dave Wyatt has a few blog posts about using secure strings and credentials.
... I also added an -AsPlainText switch to the ConvertFrom-SecureString command, in case you want to get the plain text back.
The only two ways I know how to map drives are to use plain text credentials. The only other way would be to run the script as an account that has permissions to the network location; that way you don't have to authenticate with a password.
I've run into a stumbling block for a script I'm writing and I was hoping someone more knowledgeable might be able to help me out.
To put it simply, I want a user to be able to input their password and each letter of that password be assign to variables.
$uCcuGUBIJnoORUWA = "a"
$LjN6WLzWVAaM4BQN = "b"
$5qJ79dPkDGNeIsVy = "c"
… etc.
Once this is done, the password is send to a text file and outputted as the variables. So if your password was "abc" then the text file would appear as …
HASH1 = $uCcuGUBIJnoORUWA
HASH2 = $LjN6WLzWVAaM4BQN
HASH3 = $5qJ79dPkDGNeIsVy
… and so on.
Once the password is completely written and is stored on the text file, the rest of the script uses that information to match each piece of code to figure out what the password is. It then would then type out the password using something like:
[System.Windows.Forms.SendKeys]::SendWait("$uCcuGUBIJnoORUWA$LjN6WLzWVAaM4BQN$5qJ79dPkDGNeIsVy")
Right now my script is using a hard-coded password, which is less than ideal. I'm using PS2EXE to convert the .ps1 file to an .exe file so it's not in plain-text.
I understand how to store the variables and how to get the script to output the variables as the actual letters, I'm just having some trouble figuring out a way for the user to input the password and then have it stored.
How about something better than obfuscation: actual encryption?
Store the credentials in a [PSCredential] object. The password portion of this is stored as a secure string, which is already a good thing.
To export it to a file:
$cred | Export-Clixml -Path C:\master.xml
To re-import it:
$cred = Import-Clixml -Path C:\master.xml
The important thing is that the password will be encrypted when it's written out to disk. It can only be decrypted (and therefore reimported) by the same user on the same computer.
As a result I like to make the user and computer name part of the file name. Here's an example of a script to store the credentials:
$cred = Get-Credential
$cred | Export-Clixml -Path "C:\whatever\master_$env:COMPUTERNAME-$env:USERNAME.xml"
In the script where you actually want to use it:
$cred = Import-Clixml -Path "C:\whatever\master_$env:COMPUTERNAME-$env:USERNAME.xml"
It's quite useful. By embedding the user and computer in the file name you can store multiple copies of the credentials depending on how many users need to access the creds on however many computers.
And since you might need the raw password in your script, the way to get that out of a [PSCredential] object is like so:
$cred.GetNetworkCredential().Password
I need to store some credentials for an SMTP server in my script, but naturally I don't want to password to be stored in plaintext.
So far I've been encrypting the password like this:
"password" | ConvertTo-SecureString -AsPlainText -Force |
ConvertFrom-SecureString
and using it in a script like this:
$password = "(the long string generated from above command)"
$username = "Test#testdomain.com"
$cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $username,($password | ConvertTo-SecureString)
However, when generating the $cred object I get the following error:
ConvertTo-SecureString : Key not valid for use in specified state.
Remove the ConvertFrom-SecureString and Reload it like this:
$Password = "password" | ConvertTo-SecureString -AsPlainText -Force
$username = "Test#testdomain.com"
$cred = New-Object System.Management.Automation.PsCredential($username, $Password)
Maybe Protect-String with Unprotect-String in Carbon module is what you are looking for. I use it all the time and works beautifully.
Carbon is a PowerShell module for automating the configuration of computers running Windows 7, 8, 2008, and 2012.
PLEASE READ the following carefully and think through the points before you decide this does not help the OP with his problem.
Encrypting a password using PS or .NET mechanisms is a case of "security through obscurity" unless one has a robust method to store the key. (The usual "robust methods" are "what I know", "what I am" (biometrics), and "what I have".) But obscurity is the level of security that the OP seems to be asking for ("naturally I don't want to password to be stored in plaintext"). And there's nothing wrong with that. But unlike cases where some security-through-obscurity is obtained because code is compiled, that's not the case w PS.
However, the security depends on who an "attacker" is considered to be. If you are dealing with a password that the current user generates, then the current user isn't an attacker. However it you are dealing with a password set by some other entity, but you need the user to use it, but not see it, then the current user is a potential attacker. (An example of this case: a script to join a workstation to a domain would need a user with right set of domain permissions. You might want the user to be able to join the domain as part of imaging/re-imaging his desktop, but you don't want his domain user account to have rights to join the domain, so your script uses a different set of credentials you don't want the user to know). I'm guessing the OP is asking about a case where the password is not assigned by the user. The rest of this answer addresses this case.
Using PS/.NET methods to encrypt/obtain password, is "security through obscurity" because an attacker only needs to put a breakpoint just before where password is used. With a variable name like $password it'll be easy to find a location to set the breakpoint. Obscuring the variable name (eg call the password variable $exectionContext which is a misspelling of a PS auto-variable) won't do much if 1) the script is short and/or 2) it's obvious what command requires the password.
So, instead of encrypting the password in what amounts to a fairly transparent and easy to reverse scheme, you can get what is arguably better security by just being tricky in setting $password (or whatever you call the var) to it's ultimate value. For example if the password is "join-thE_domain" you could do something like:
...other script code...
$windowTitle="Install/deinstaller joint script"
...other script code...
$paramName = "-th"
...other script code...
$status = "End main"
...other script code...
$subTitle = $windowTitle.substring(20,4)
...other script code...
$count = 32
...other script code...
# Use a regex in the following to make it more obscure
$fixedStatus = $status -replace "n","_" -replace "o",[string][char]$count
...other script code...
# If cmdlet/cmd doesn't support password as a positional parameter then
# write a function that calls cmdlet/cmd and takes password as positional parm
cmdlet-that-needs-password "arg value 1" ("$subTitle$paramName"+$fixedStatus) "arg value 3"
...other script code...
# extra code at the bottom is important to keep someone from
# just scrolling to bottom of script to see password being used
# This extra code could be just dummy code that doesn't really do anything
# Extra code can be placed throughout the script to make it more obscure
...other script code...